diff --git a/CMakeLists.txt b/CMakeLists.txt index 38a7072f10..1a20eed63d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,9 +69,9 @@ set(TITLE_SEQUENCE_VERSION "0.4.14") set(TITLE_SEQUENCE_URL "https://github.com/OpenRCT2/title-sequences/releases/download/v${TITLE_SEQUENCE_VERSION}/title-sequences.zip") set(TITLE_SEQUENCE_SHA1 "6c04781b959b468e1f65ec2d2f21f5aaa5e5724d") -set(OBJECTS_VERSION "1.5.0") +set(OBJECTS_VERSION "1.5.1") set(OBJECTS_URL "https://github.com/OpenRCT2/objects/releases/download/v${OBJECTS_VERSION}/objects.zip") -set(OBJECTS_SHA1 "90c26f416ddaeb0c35490b7af89f4c6f9d6351f3") +set(OBJECTS_SHA1 "e922b9fd779e7752176f1d0d8766c2ee6ad1e41b") set(OPENSFX_VERSION "1.0.5") set(OPENSFX_URL "https://github.com/OpenRCT2/OpenSoundEffects/releases/download/v${OPENSFX_VERSION}/opensound.zip") @@ -81,9 +81,9 @@ set(OPENMSX_VERSION "1.6") set(OPENMSX_URL "https://github.com/OpenRCT2/OpenMusic/releases/download/v${OPENMSX_VERSION}/openmusic.zip") set(OPENMSX_SHA1 "ba170fa6d777b309c15420f4b6eb3fa25082a9d1") -set(REPLAYS_VERSION "0.0.85") +set(REPLAYS_VERSION "0.0.86") set(REPLAYS_URL "https://github.com/OpenRCT2/replays/releases/download/v${REPLAYS_VERSION}/replays.zip") -set(REPLAYS_SHA1 "2B0939953A41D2CE82809CB7C21FC3883578383F") +set(REPLAYS_SHA1 "637E73F20C03DCD52ACA36FAEE15DADB31797FE0") option(FORCE32 "Force 32-bit build. It will add `-m32` to compiler flags.") option(WITH_TESTS "Build tests") diff --git a/data/language/en-GB.txt b/data/language/en-GB.txt index af3b4df569..7bc26d4c2c 100644 --- a/data/language/en-GB.txt +++ b/data/language/en-GB.txt @@ -2169,7 +2169,6 @@ STR_3136 :Warning: This design will be built with an alternative vehicle type STR_3137 :Select Nearby Scenery STR_3138 :Reset Selection STR_3139 :Cable lift unable to work in this operating mode -STR_3140 :Cable lift hill must start immediately after station STR_3141 :Multi-circuit per ride not possible with cable lift hill STR_3142 :{WINDOW_COLOUR_2}Capacity: {BLACK}{STRINGID} STR_3143 :Show people on map @@ -3790,5 +3789,8 @@ STR_6723 :At least one entertainer peep animations object must be selected STR_6724 :Scenario Texts STR_6725 :X: STR_6726 :Y: -STR_6727 :Export emscripten data -STR_6728 :Import emscripten data +STR_6727 :Dive Loop (left) +STR_6728 :Dive Loop (right) +STR_6729 :Cable lift hill must start immediately after station or block brake +STR_6730 :Export emscripten data +STR_6731 :Import emscripten data diff --git a/data/language/ko-KR.txt b/data/language/ko-KR.txt index 8407e0017f..c6663f8fdc 100644 --- a/data/language/ko-KR.txt +++ b/data/language/ko-KR.txt @@ -2610,7 +2610,7 @@ STR_5368 :충돌 이력 제거 STR_5371 :오브젝트 선택 STR_5372 :마우스 오른쪽 드래그 시 좌우 반전 STR_5373 :이름 {STRINGID} -STR_5374 :날짜 {STRINGID} +STR_5374 :수정 날짜 {STRINGID} STR_5375 :▲ STR_5376 :▼ STR_5404 :이미 존재하는 이름입니다 @@ -3506,9 +3506,9 @@ STR_6437 :보이기 STR_6438 :{MOVE_X}{2}👁 STR_6439 :칸 조사 창: 감춤 여부 STR_6440 :물 투명하게 보기 -STR_6441 :최소 하나 이상의 일반 보도 바닥 오브젝트를 선택해야 합니다. -STR_6442 :최소 하나 이상의 대기 줄 보도 바닥 오브젝트를 선택해야 합니다. -STR_6443 :최소 하나 이상의 보도 난간 오브젝트를 선택해야 합니다. +STR_6441 :최소 하나 이상의 일반 보도 바닥 오브젝트를 선택해야 합니다 +STR_6442 :최소 하나 이상의 대기 줄 보도 바닥 오브젝트를 선택해야 합니다 +STR_6443 :최소 하나 이상의 보도 난간 오브젝트를 선택해야 합니다 STR_6444 :보도 바닥 STR_6445 :보도 난간 STR_6446 :{WINDOW_COLOUR_2}바닥 이름: {BLACK}{STRINGID} @@ -3775,3 +3775,19 @@ STR_6707 :(선택 안 함) STR_6708 :부드러움 강도 STR_6709 :부드러움 강도를 {COMMA16}∼{COMMA16} 사이의 값으로 입력하세요 STR_6710 :안정된 정렬 +STR_6711 :파일 이름: +STR_6712 :저장 +STR_6713 :{COMMA32} {STRINGID} +STR_6714 :파일 이름 +STR_6715 :수정 날짜 +STR_6716 :파일 크기 +STR_6717 :파일 크기 {STRINGID} +STR_6718 :손님 애니메이션 +STR_6719 :최소 하나 이상의 손님 애니메이션 오브젝트를 선택해야 합니다 +STR_6720 :최소 하나 이상의 미화원 애니메이션 오브젝트를 선택해야 합니다 +STR_6721 :최소 하나 이상의 정비기술자 애니메이션 오브젝트를 선택해야 합니다 +STR_6722 :최소 하나 이상의 경비원 애니메이션 오브젝트를 선택해야 합니다 +STR_6723 :최소 하나 이상의 엔터테이너 애니메이션 오브젝트를 선택해야 합니다 +STR_6724 :시나리오 텍스트 +STR_6725 :X: +STR_6726 :Y: diff --git a/data/language/nl-NL.txt b/data/language/nl-NL.txt index a653cdeb36..589f087900 100644 --- a/data/language/nl-NL.txt +++ b/data/language/nl-NL.txt @@ -2607,7 +2607,7 @@ STR_5368 :Crashstatus weg STR_5371 :Objectselectie STR_5372 :Sleeprichting van rechtermuisknop omkeren STR_5373 :Naam {STRINGID} -STR_5374 :Datum {STRINGID} +STR_5374 :Gewijzigd {STRINGID} STR_5375 :▲ STR_5376 :▼ STR_5404 :Naam bestaat al @@ -3773,3 +3773,8 @@ STR_6709 :Voer een afrondsterkte in tussen {COMMA16} en {COMMA16} STR_6710 :Stabiel sorteren STR_6711 :Bestandsnaam: STR_6712 :Opslaan +STR_6713 :{COMMA32} {STRINGID} +STR_6714 :Naam +STR_6715 :Gewijzigd +STR_6716 :Grootte +STR_6717 :Grootte {STRINGID} diff --git a/data/language/pl-PL.txt b/data/language/pl-PL.txt index aec3b5cae6..c9eec9dbcb 100644 --- a/data/language/pl-PL.txt +++ b/data/language/pl-PL.txt @@ -1093,7 +1093,7 @@ STR_1698 :Można to umieścić jedynie na ścieżce kolejki STR_1699 :Za dużo ludzi w grze STR_1700 :Zatrudnij dozorcę STR_1701 :Zatrudnij mechanika -STR_1702 :Zatrudnij ochroniarza +STR_1702 :Zatrudnij strażnika STR_1703 :Zatrudnij komika STR_1704 :Nie można zatrudnić nowych pracowników… STR_1705 :Zwolnij pracownika @@ -2000,7 +2000,7 @@ STR_2804 :Podświetl tych pracowników na mapie STR_2805 :Pokaż plan parku STR_2806 :{RED}Goście skarżą się na fatalny stan ścieżek w twoim parku{NEWLINE}Sprawdź gdzie znajdują się twoi dozorcy i rozważ lepszą organizacje ich pracy STR_2807 :{RED}Goście skarżą się na śmieci leżące na ziemi w twoim parku{NEWLINE}Sprawdź gdzie znajdują się twoi dozorcy i rozważ lepszą organizację ich pracy -STR_2808 :{RED}Goście skarzą się na wandalizm w twoim parku{NEWLINE}Sprawdź gdzie znajdują się twoi ochroniarze i rozważ poprawę organizacji ich pracy +STR_2808 :{RED}Goście skarzą się na wandalizm w twoim parku{NEWLINE}Sprawdź gdzie znajdują się twoi strażnicy i rozważ poprawę organizacji ich pracy STR_2809 :{RED}Goście są głodni i nie mogą znaleźć miejsca gdzie mogliby kupić coś do jedzenia STR_2810 :{RED}Goście są spragnieni i nie mogą znaleźć miejsca gdzie mogliby kupić jakieś napoje STR_2811 :{RED}Goście się skarżą, że w twoim parku bardzo ciężko jest znaleźć toaletę @@ -2201,7 +2201,7 @@ STR_3188 :Znaki drogowe STR_3189 :Klasyczne ścieżki STR_3190 :Dodatki drogowe STR_3191 :Grupa scenerii -STR_3192 :Wejście do parku +STR_3192 :Wejścia do parku STR_3193 :Woda STR_3195 :Lista wynalazków STR_3196 :{WINDOW_COLOUR_2}Grupa badawcza: {BLACK}{STRINGID} @@ -3736,8 +3736,8 @@ STR_6671 :Pokazuj „prawdziwe” imiona pracowników STR_6672 :Przełącz między pokazywaniem imion pracowników a numerami STR_6673 :Przezroczyste STR_6674 :{MONTH}, Rok {COMMA16} -STR_6675 :Imiona gości -STR_6676 :Co najmniej jeden obiekt z nazwami gości musi być wybrany +STR_6675 :Imiona postaci +STR_6676 :Należy wybrać co najmniej jeden obiekt z nazwami postaci STR_6677 :Dodaj plaże wokół zbiorników wodnych STR_6678 :Źródło mapy wysokości: STR_6679 :Równina @@ -3779,3 +3779,12 @@ STR_6714 :Nazwa pliku STR_6715 :Data modyfikacji STR_6716 :Rozmiar pliku STR_6717 :Rozmiar {STRINGID} +STR_6718 :Animacje postaci +STR_6719 :Należy wybrać co najmniej jeden obiekt animacji gościa +STR_6720 :Należy wybrać co najmniej jeden obiekt animacji dozorcy +STR_6721 :Należy wybrać co najmniej jeden obiekt animacji mechanika +STR_6722 :Należy wybrać co najmniej jeden obiekt animacji strażnika +STR_6723 :Należy wybrać co najmniej jeden obiekt animacji komika +STR_6724 :Teksty scenariuszy +STR_6725 :X: +STR_6726 :Y: diff --git a/data/language/pt-BR.txt b/data/language/pt-BR.txt index f5dddab6c8..5ce468928b 100644 --- a/data/language/pt-BR.txt +++ b/data/language/pt-BR.txt @@ -2201,7 +2201,7 @@ STR_3188 :Placa para Caminho STR_3189 :Calçadas Obsoletas STR_3190 :Caminhos Extras STR_3191 :Grupo de Cenários -STR_3192 :Entrada do Parque +STR_3192 :Entradas dos Parques STR_3193 :Água STR_3195 :Lista de Invenções STR_3196 :{WINDOW_COLOUR_2}Grupo de Pesquisa: {BLACK}{STRINGID} @@ -3785,3 +3785,6 @@ STR_6720 :Ao menos um objeto de animação de pessoinha de faxineiro deve ser STR_6721 :Ao menos um objeto de animação de pessoinha de mecânico deve ser selecionado STR_6722 :Ao menos um objeto de animação de pessoinha de segurança deve ser selecionado STR_6723 :Ao menos um objeto de animação de pessoinha de animador deve ser selecionado +STR_6724 :Textos dos Cenários +STR_6725 :X: +STR_6726 :Y: diff --git a/data/language/ru-RU.txt b/data/language/ru-RU.txt index d6b62380b7..3897aa8241 100644 --- a/data/language/ru-RU.txt +++ b/data/language/ru-RU.txt @@ -2162,7 +2162,6 @@ STR_3136 :Внимание: Этот дизайн будет построен STR_3137 :Выберите Ближайший Пейзаж STR_3138 :Сброс Выбора STR_3139 :Кабельный лифт не может работать в этом режиме -STR_3140 :Кабельный лифт должен начинаться сразу после станции STR_3141 :Мульти-кольца невозможны с кабельным лифтом STR_3142 :{WINDOW_COLOUR_2}Вместимость: {BLACK}{STRINGID} STR_3143 :Показать людей на карте @@ -2194,7 +2193,7 @@ STR_3188 :Знаки STR_3189 :Дорожки STR_3190 :Доп. пути STR_3191 :Группы пейзажа -STR_3192 :Вход в парк +STR_3192 :Входы в парк STR_3193 :Вода STR_3195 :Изобретения STR_3196 :{WINDOW_COLOUR_2} Разработка: {BLACK}{STRINGID} @@ -3773,3 +3772,7 @@ STR_6720 :Нужно выбрать хотя бы один объект ан STR_6721 :Нужно выбрать хотя бы один объект анимации механиков STR_6722 :Нужно выбрать хотя бы один объект анимации охранников STR_6723 :Нужно выбрать хотя бы один объект анимации развлекателей +STR_6724 :Тексты сценариев +STR_6725 :X: +STR_6726 :Y: +STR_6729 :Кабельный лифт должен начинаться сразу после станции или блок-тормоза diff --git a/distribution/changelog.txt b/distribution/changelog.txt index bf3503ffd9..93c5199f49 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -1,13 +1,19 @@ 0.4.19 (in development) ------------------------------------------------------------------------ - Feature: [#23328] Introducing peep animation objects, enabling custom entertainer costumes. +- Feature: [#23569] Add large diagonal flat to steep and dive loop track pieces. +- Improved: [#20683] Allow Giga Coaster cable lift to start after block brake section. - Improved: [#23328] The costume list in the staff window is now ordered alphabetically. - Improved: [#23540] The file browser now optionally shows a file size column. - Change: [#23328] All RCT2 entertainer costumes are now available in legacy parks. +- Fix: [#1479] Incorrect values provided by the in game console “get location” command. - Fix: [#21794] Lay-down coaster cars reverse on first frames of downwards corkscrew. +- Fix: [#23368] Incorrect refund amount when deleting track pieces at or above 96m. - Fix: [#23508] Simultaneous virtual floors shown for ride and footpath. +- Fix: [#23512] Holding brakes are skipped if they’re too close together. - Fix: [#23581] [Plugin] Food/drink items given to guests have no consumption duration set. - Fix: [#23591] “Install new track” button in Track Designs Manager is misaligned. +- Fix: [#23618] Can no longer build diagonal brakes & block brakes on Steeplechase, Inverted Lay-down, & Inverted Multi-Dim roller coasters. 0.4.18 (2025-01-08) ------------------------------------------------------------------------ diff --git a/distribution/openrct2.d.ts b/distribution/openrct2.d.ts index 24b36a1244..a9bf7f0c80 100644 --- a/distribution/openrct2.d.ts +++ b/distribution/openrct2.d.ts @@ -4874,6 +4874,9 @@ declare global { frameBase: number; frameCount?: number; frameDuration?: number; + primaryColour?: number; + secondaryColour?: number; + tertiaryColour?: number; offset?: ScreenCoordsXY; } diff --git a/distribution/windows/readme.md b/distribution/windows/readme.md index 573a74915b..d684897d39 100644 --- a/distribution/windows/readme.md +++ b/distribution/windows/readme.md @@ -1,6 +1,4 @@ # Windows Installer This directory contains the script and resources for the Windows installer. The installer is created using [Nullsoft Scriptable Install System (NSIS)](http://nsis.sourceforge.net) version v3.0a0+. -As there is currently only a 32 bit version of OpenRCT2 available, the architecture and windows version checks have been disabled. These will be re-enabled once OpenRCT2 is a stand alone executable. - Code based on [OpenTTD](http://openttd.org) installer. diff --git a/openrct2.proj b/openrct2.proj index 4ec99e95d6..179c9a9f12 100644 --- a/openrct2.proj +++ b/openrct2.proj @@ -45,14 +45,14 @@ 9984c1e317dcfb3aaf8e17f1db2ebb0f771e2373 https://github.com/OpenRCT2/title-sequences/releases/download/v0.4.14/title-sequences.zip 6c04781b959b468e1f65ec2d2f21f5aaa5e5724d - https://github.com/OpenRCT2/objects/releases/download/v1.5.0/objects.zip - 90c26f416ddaeb0c35490b7af89f4c6f9d6351f3 + https://github.com/OpenRCT2/objects/releases/download/v1.5.1/objects.zip + e922b9fd779e7752176f1d0d8766c2ee6ad1e41b https://github.com/OpenRCT2/OpenSoundEffects/releases/download/v1.0.5/opensound.zip b1b1f1b241d2cbff63a1889c4dc5a09bdf769bfb https://github.com/OpenRCT2/OpenMusic/releases/download/v1.6/openmusic.zip ba170fa6d777b309c15420f4b6eb3fa25082a9d1 - https://github.com/OpenRCT2/replays/releases/download/v0.0.85/replays.zip - 2B0939953A41D2CE82809CB7C21FC3883578383F + https://github.com/OpenRCT2/replays/releases/download/v0.0.86/replays.zip + 637E73F20C03DCD52ACA36FAEE15DADB31797FE0 diff --git a/readme.md b/readme.md index c592acc44f..dba893e4e3 100644 --- a/readme.md +++ b/readme.md @@ -226,7 +226,7 @@ OpenRCT2 requires original files of RollerCoaster Tycoon 2 to play. It can be bo --- # 4. Contributing -OpenRCT2 uses the [gitflow workflow](https://www.atlassian.com/git/tutorials/comparing-workflows#gitflow-workflow). If you are implementing a new feature or logic from the original game, please branch off and perform pull requests to ```develop```. If you are fixing a bug for the next release, please branch off and perform pull requests to the correct release branch. ```master``` only contains tagged releases, you should never branch off this. +OpenRCT2 uses the [gitflow workflow](https://www.atlassian.com/git/tutorials/comparing-workflows#gitflow-workflow). If you are implementing a new feature or fixing a bug, please branch off and perform pull requests to ```develop```. ```master``` only contains tagged releases, you should never branch off this. Please read our [contributing guidelines](https://github.com/OpenRCT2/OpenRCT2/blob/develop/CONTRIBUTING.md) for information. diff --git a/resources/g2/sprites.json b/resources/g2/sprites.json index 4137a78b68..b9842c0b7d 100644 --- a/resources/g2/sprites.json +++ b/resources/g2/sprites.json @@ -6597,6 +6597,342 @@ "y": -22, "palette": "keep" }, + { + "path": "track/lattice_triangle/flat_to_steep_up_diag_1_1.png", + "x": -32, + "y": -6, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/flat_to_steep_up_diag_1_2.png", + "x": -32, + "y": -25, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/flat_to_steep_up_diag_1_3.png", + "x": -32, + "y": -44, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/flat_to_steep_up_diag_2_1.png", + "x": -8, + "y": -10, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/flat_to_steep_up_diag_2_2.png", + "x": 0, + "y": 0, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/flat_to_steep_up_diag_2_3.png", + "x": -8, + "y": -26, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/flat_to_steep_up_diag_3_1.png", + "x": -32, + "y": -6, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/flat_to_steep_up_diag_3_2.png", + "x": -32, + "y": -25, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/flat_to_steep_up_diag_3_3.png", + "x": -32, + "y": -44, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/flat_to_steep_up_diag_4_1.png", + "x": -8, + "y": -16, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/flat_to_steep_up_diag_4_2.png", + "x": -8, + "y": -48, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/flat_to_steep_up_diag_4_3.png", + "x": -8, + "y": -89, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/steep_to_flat_up_diag_1_1.png", + "x": -32, + "y": -47, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/steep_to_flat_up_diag_1_2.png", + "x": -32, + "y": -20, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/steep_to_flat_up_diag_1_3.png", + "x": -32, + "y": -5, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/steep_to_flat_up_diag_2_1.png", + "x": 0, + "y": 0, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/steep_to_flat_up_diag_2_2.png", + "x": 0, + "y": 0, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/steep_to_flat_up_diag_2_3.png", + "x": -8, + "y": -14, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/steep_to_flat_up_diag_3_1.png", + "x": -32, + "y": -47, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/steep_to_flat_up_diag_3_2.png", + "x": -32, + "y": -20, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/steep_to_flat_up_diag_3_3.png", + "x": -32, + "y": -5, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/steep_to_flat_up_diag_4_1.png", + "x": -8, + "y": -32, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/steep_to_flat_up_diag_4_2.png", + "x": -8, + "y": -72, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/steep_to_flat_up_diag_4_3.png", + "x": -8, + "y": -42, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/dive_loop_45_left_1_1.png", + "x": -32, + "y": -31, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/dive_loop_45_left_1_2.png", + "x": -32, + "y": -41, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/dive_loop_45_left_1_3.png", + "x": -31, + "y": -41, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/dive_loop_45_left_1_4.png", + "x": -18, + "y": -23, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/dive_loop_45_left_2_1.png", + "x": -8, + "y": 12, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/dive_loop_45_left_2_2.png", + "x": -7, + "y": -27, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/dive_loop_45_left_2_3.png", + "x": -25, + "y": -25, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/dive_loop_45_left_2_4.png", + "x": -28, + "y": -13, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/dive_loop_45_left_3_1.png", + "x": 0, + "y": -33, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/dive_loop_45_left_3_2.png", + "x": -14, + "y": -27, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/dive_loop_45_left_3_3.png", + "x": -24, + "y": -21, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/dive_loop_45_left_3_4.png", + "x": -22, + "y": -14, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/dive_loop_45_left_4_1.png", + "x": -11, + "y": -32, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/dive_loop_45_left_4_2.png", + "x": -45, + "y": -83, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/dive_loop_45_left_4_3.png", + "x": -24, + "y": -40, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/dive_loop_45_left_4_4.png", + "x": -22, + "y": -23, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/dive_loop_45_right_1_1.png", + "x": -32, + "y": -33, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/dive_loop_45_right_1_2.png", + "x": -32, + "y": -27, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/dive_loop_45_right_1_3.png", + "x": -28, + "y": -21, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/dive_loop_45_right_1_4.png", + "x": -32, + "y": -14, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/dive_loop_45_right_2_1.png", + "x": -9, + "y": 12, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/dive_loop_45_right_2_2.png", + "x": -20, + "y": -27, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/dive_loop_45_right_2_3.png", + "x": -11, + "y": -25, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/dive_loop_45_right_2_4.png", + "x": -22, + "y": -13, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/dive_loop_45_right_3_1.png", + "x": 0, + "y": -31, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/dive_loop_45_right_3_2.png", + "x": -12, + "y": -41, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/dive_loop_45_right_3_3.png", + "x": -24, + "y": -41, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/dive_loop_45_right_3_4.png", + "x": -22, + "y": -23, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/dive_loop_45_right_4_1.png", + "x": -8, + "y": -32, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/dive_loop_45_right_4_2.png", + "x": -4, + "y": -83, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/dive_loop_45_right_4_3.png", + "x": -30, + "y": -40, + "palette": "keep" + }, + { + "path": "track/lattice_triangle/dive_loop_45_right_4_4.png", + "x": -23, + "y": -23, + "palette": "keep" + }, { "path": "track/mini/booster_1.png", "x": -22, @@ -8741,6 +9077,342 @@ "y": -29, "palette": "keep" }, + { + "path": "track/bm/flat_to_steep_up_diag_1_1.png", + "x": -32, + "y": -7, + "palette": "keep" + }, + { + "path": "track/bm/flat_to_steep_up_diag_1_2.png", + "x": -32, + "y": -27, + "palette": "keep" + }, + { + "path": "track/bm/flat_to_steep_up_diag_1_3.png", + "x": -32, + "y": -46, + "palette": "keep" + }, + { + "path": "track/bm/flat_to_steep_up_diag_2_1.png", + "x": -13, + "y": -9, + "palette": "keep" + }, + { + "path": "track/bm/flat_to_steep_up_diag_2_2.png", + "x": 0, + "y": 0, + "palette": "keep" + }, + { + "path": "track/bm/flat_to_steep_up_diag_2_3.png", + "x": -13, + "y": -24, + "palette": "keep" + }, + { + "path": "track/bm/flat_to_steep_up_diag_3_1.png", + "x": -32, + "y": -7, + "palette": "keep" + }, + { + "path": "track/bm/flat_to_steep_up_diag_3_2.png", + "x": -32, + "y": -26, + "palette": "keep" + }, + { + "path": "track/bm/flat_to_steep_up_diag_3_3.png", + "x": -32, + "y": -45, + "palette": "keep" + }, + { + "path": "track/bm/flat_to_steep_up_diag_4_1.png", + "x": -13, + "y": -16, + "palette": "keep" + }, + { + "path": "track/bm/flat_to_steep_up_diag_4_2.png", + "x": -13, + "y": -48, + "palette": "keep" + }, + { + "path": "track/bm/flat_to_steep_up_diag_4_3.png", + "x": -13, + "y": -88, + "palette": "keep" + }, + { + "path": "track/bm/steep_to_flat_up_diag_1_1.png", + "x": -32, + "y": -49, + "palette": "keep" + }, + { + "path": "track/bm/steep_to_flat_up_diag_1_2.png", + "x": -32, + "y": -21, + "palette": "keep" + }, + { + "path": "track/bm/steep_to_flat_up_diag_1_3.png", + "x": -32, + "y": -7, + "palette": "keep" + }, + { + "path": "track/bm/steep_to_flat_up_diag_2_1.png", + "x": 0, + "y": 0, + "palette": "keep" + }, + { + "path": "track/bm/steep_to_flat_up_diag_2_2.png", + "x": 0, + "y": 0, + "palette": "keep" + }, + { + "path": "track/bm/steep_to_flat_up_diag_2_3.png", + "x": -13, + "y": -13, + "palette": "keep" + }, + { + "path": "track/bm/steep_to_flat_up_diag_3_1.png", + "x": -32, + "y": -48, + "palette": "keep" + }, + { + "path": "track/bm/steep_to_flat_up_diag_3_2.png", + "x": -32, + "y": -21, + "palette": "keep" + }, + { + "path": "track/bm/steep_to_flat_up_diag_3_3.png", + "x": -32, + "y": -7, + "palette": "keep" + }, + { + "path": "track/bm/steep_to_flat_up_diag_4_1.png", + "x": -13, + "y": -32, + "palette": "keep" + }, + { + "path": "track/bm/steep_to_flat_up_diag_4_2.png", + "x": -13, + "y": -72, + "palette": "keep" + }, + { + "path": "track/bm/steep_to_flat_up_diag_4_3.png", + "x": -13, + "y": -41, + "palette": "keep" + }, + { + "path": "track/bm/dive_loop_45_left_1_1.png", + "x": -32, + "y": -32, + "palette": "keep" + }, + { + "path": "track/bm/dive_loop_45_left_1_2.png", + "x": -32, + "y": -47, + "palette": "keep" + }, + { + "path": "track/bm/dive_loop_45_left_1_3.png", + "x": -32, + "y": -44, + "palette": "keep" + }, + { + "path": "track/bm/dive_loop_45_left_1_4.png", + "x": -20, + "y": -22, + "palette": "keep" + }, + { + "path": "track/bm/dive_loop_45_left_2_1.png", + "x": -13, + "y": 12, + "palette": "keep" + }, + { + "path": "track/bm/dive_loop_45_left_2_2.png", + "x": -12, + "y": -27, + "palette": "keep" + }, + { + "path": "track/bm/dive_loop_45_left_2_3.png", + "x": -26, + "y": -23, + "palette": "keep" + }, + { + "path": "track/bm/dive_loop_45_left_2_4.png", + "x": -27, + "y": -12, + "palette": "keep" + }, + { + "path": "track/bm/dive_loop_45_left_3_1.png", + "x": 0, + "y": -36, + "palette": "keep" + }, + { + "path": "track/bm/dive_loop_45_left_3_2.png", + "x": -19, + "y": -29, + "palette": "keep" + }, + { + "path": "track/bm/dive_loop_45_left_3_3.png", + "x": -37, + "y": -20, + "palette": "keep" + }, + { + "path": "track/bm/dive_loop_45_left_3_4.png", + "x": -26, + "y": -12, + "palette": "keep" + }, + { + "path": "track/bm/dive_loop_45_left_4_1.png", + "x": -16, + "y": -32, + "palette": "keep" + }, + { + "path": "track/bm/dive_loop_45_left_4_2.png", + "x": -60, + "y": -96, + "palette": "keep" + }, + { + "path": "track/bm/dive_loop_45_left_4_3.png", + "x": -28, + "y": -40, + "palette": "keep" + }, + { + "path": "track/bm/dive_loop_45_left_4_4.png", + "x": -25, + "y": -22, + "palette": "keep" + }, + { + "path": "track/bm/dive_loop_45_right_1_1.png", + "x": -32, + "y": -37, + "palette": "keep" + }, + { + "path": "track/bm/dive_loop_45_right_1_2.png", + "x": -32, + "y": -30, + "palette": "keep" + }, + { + "path": "track/bm/dive_loop_45_right_1_3.png", + "x": -30, + "y": -21, + "palette": "keep" + }, + { + "path": "track/bm/dive_loop_45_right_1_4.png", + "x": -32, + "y": -12, + "palette": "keep" + }, + { + "path": "track/bm/dive_loop_45_right_2_1.png", + "x": -15, + "y": 12, + "palette": "keep" + }, + { + "path": "track/bm/dive_loop_45_right_2_2.png", + "x": -25, + "y": -27, + "palette": "keep" + }, + { + "path": "track/bm/dive_loop_45_right_2_3.png", + "x": -13, + "y": -23, + "palette": "keep" + }, + { + "path": "track/bm/dive_loop_45_right_2_4.png", + "x": -26, + "y": -12, + "palette": "keep" + }, + { + "path": "track/bm/dive_loop_45_right_3_1.png", + "x": 0, + "y": -31, + "palette": "keep" + }, + { + "path": "track/bm/dive_loop_45_right_3_2.png", + "x": -14, + "y": -45, + "palette": "keep" + }, + { + "path": "track/bm/dive_loop_45_right_3_3.png", + "x": -28, + "y": -43, + "palette": "keep" + }, + { + "path": "track/bm/dive_loop_45_right_3_4.png", + "x": -25, + "y": -22, + "palette": "keep" + }, + { + "path": "track/bm/dive_loop_45_right_4_1.png", + "x": -13, + "y": -32, + "palette": "keep" + }, + { + "path": "track/bm/dive_loop_45_right_4_2.png", + "x": -9, + "y": -89, + "palette": "keep" + }, + { + "path": "track/bm/dive_loop_45_right_4_3.png", + "x": -31, + "y": -40, + "palette": "keep" + }, + { + "path": "track/bm/dive_loop_45_right_4_4.png", + "x": -24, + "y": -22, + "palette": "keep" + }, { "path": "track/railway/quarter_turn_3_tiles_sw_se_part_3.png", "x": -8, @@ -19212,6 +19884,342 @@ "y": -25, "palette": "keep" }, + { + "path": "track/corkscrew/flat_to_steep_up_diag_1_1.png", + "x": -32, + "y": -6, + "palette": "keep" + }, + { + "path": "track/corkscrew/flat_to_steep_up_diag_1_2.png", + "x": -32, + "y": -26, + "palette": "keep" + }, + { + "path": "track/corkscrew/flat_to_steep_up_diag_1_3.png", + "x": -32, + "y": -44, + "palette": "keep" + }, + { + "path": "track/corkscrew/flat_to_steep_up_diag_2_1.png", + "x": -14, + "y": -8, + "palette": "keep" + }, + { + "path": "track/corkscrew/flat_to_steep_up_diag_2_2.png", + "x": 0, + "y": 0, + "palette": "keep" + }, + { + "path": "track/corkscrew/flat_to_steep_up_diag_2_3.png", + "x": -14, + "y": -25, + "palette": "keep" + }, + { + "path": "track/corkscrew/flat_to_steep_up_diag_3_1.png", + "x": -32, + "y": -6, + "palette": "keep" + }, + { + "path": "track/corkscrew/flat_to_steep_up_diag_3_2.png", + "x": -32, + "y": -26, + "palette": "keep" + }, + { + "path": "track/corkscrew/flat_to_steep_up_diag_3_3.png", + "x": -32, + "y": -44, + "palette": "keep" + }, + { + "path": "track/corkscrew/flat_to_steep_up_diag_4_1.png", + "x": -14, + "y": -16, + "palette": "keep" + }, + { + "path": "track/corkscrew/flat_to_steep_up_diag_4_2.png", + "x": -14, + "y": -48, + "palette": "keep" + }, + { + "path": "track/corkscrew/flat_to_steep_up_diag_4_3.png", + "x": -14, + "y": -88, + "palette": "keep" + }, + { + "path": "track/corkscrew/steep_to_flat_up_diag_1_1.png", + "x": -32, + "y": -48, + "palette": "keep" + }, + { + "path": "track/corkscrew/steep_to_flat_up_diag_1_2.png", + "x": -32, + "y": -20, + "palette": "keep" + }, + { + "path": "track/corkscrew/steep_to_flat_up_diag_1_3.png", + "x": -32, + "y": -6, + "palette": "keep" + }, + { + "path": "track/corkscrew/steep_to_flat_up_diag_2_1.png", + "x": 0, + "y": 0, + "palette": "keep" + }, + { + "path": "track/corkscrew/steep_to_flat_up_diag_2_2.png", + "x": 0, + "y": 0, + "palette": "keep" + }, + { + "path": "track/corkscrew/steep_to_flat_up_diag_2_3.png", + "x": -14, + "y": -13, + "palette": "keep" + }, + { + "path": "track/corkscrew/steep_to_flat_up_diag_3_1.png", + "x": -32, + "y": -48, + "palette": "keep" + }, + { + "path": "track/corkscrew/steep_to_flat_up_diag_3_2.png", + "x": -32, + "y": -20, + "palette": "keep" + }, + { + "path": "track/corkscrew/steep_to_flat_up_diag_3_3.png", + "x": -32, + "y": -6, + "palette": "keep" + }, + { + "path": "track/corkscrew/steep_to_flat_up_diag_4_1.png", + "x": -14, + "y": -32, + "palette": "keep" + }, + { + "path": "track/corkscrew/steep_to_flat_up_diag_4_2.png", + "x": -14, + "y": -72, + "palette": "keep" + }, + { + "path": "track/corkscrew/steep_to_flat_up_diag_4_3.png", + "x": -14, + "y": -40, + "palette": "keep" + }, + { + "path": "track/corkscrew/dive_loop_45_left_1_1.png", + "x": -32, + "y": -30, + "palette": "keep" + }, + { + "path": "track/corkscrew/dive_loop_45_left_1_2.png", + "x": -32, + "y": -46, + "palette": "keep" + }, + { + "path": "track/corkscrew/dive_loop_45_left_1_3.png", + "x": -32, + "y": -44, + "palette": "keep" + }, + { + "path": "track/corkscrew/dive_loop_45_left_1_4.png", + "x": -21, + "y": -17, + "palette": "keep" + }, + { + "path": "track/corkscrew/dive_loop_45_left_2_1.png", + "x": -14, + "y": 12, + "palette": "keep" + }, + { + "path": "track/corkscrew/dive_loop_45_left_2_2.png", + "x": -13, + "y": -27, + "palette": "keep" + }, + { + "path": "track/corkscrew/dive_loop_45_left_2_3.png", + "x": -27, + "y": -20, + "palette": "keep" + }, + { + "path": "track/corkscrew/dive_loop_45_left_2_4.png", + "x": -26, + "y": -10, + "palette": "keep" + }, + { + "path": "track/corkscrew/dive_loop_45_left_3_1.png", + "x": 0, + "y": -35, + "palette": "keep" + }, + { + "path": "track/corkscrew/dive_loop_45_left_3_2.png", + "x": -19, + "y": -31, + "palette": "keep" + }, + { + "path": "track/corkscrew/dive_loop_45_left_3_3.png", + "x": -40, + "y": -15, + "palette": "keep" + }, + { + "path": "track/corkscrew/dive_loop_45_left_3_4.png", + "x": -24, + "y": -8, + "palette": "keep" + }, + { + "path": "track/corkscrew/dive_loop_45_left_4_1.png", + "x": -17, + "y": -32, + "palette": "keep" + }, + { + "path": "track/corkscrew/dive_loop_45_left_4_2.png", + "x": -55, + "y": -90, + "palette": "keep" + }, + { + "path": "track/corkscrew/dive_loop_45_left_4_3.png", + "x": -28, + "y": -40, + "palette": "keep" + }, + { + "path": "track/corkscrew/dive_loop_45_left_4_4.png", + "x": -24, + "y": -17, + "palette": "keep" + }, + { + "path": "track/corkscrew/dive_loop_45_right_1_1.png", + "x": -32, + "y": -35, + "palette": "keep" + }, + { + "path": "track/corkscrew/dive_loop_45_right_1_2.png", + "x": -32, + "y": -31, + "palette": "keep" + }, + { + "path": "track/corkscrew/dive_loop_45_right_1_3.png", + "x": -31, + "y": -15, + "palette": "keep" + }, + { + "path": "track/corkscrew/dive_loop_45_right_1_4.png", + "x": -32, + "y": -8, + "palette": "keep" + }, + { + "path": "track/corkscrew/dive_loop_45_right_2_1.png", + "x": -15, + "y": 12, + "palette": "keep" + }, + { + "path": "track/corkscrew/dive_loop_45_right_2_2.png", + "x": -24, + "y": -27, + "palette": "keep" + }, + { + "path": "track/corkscrew/dive_loop_45_right_2_3.png", + "x": -13, + "y": -20, + "palette": "keep" + }, + { + "path": "track/corkscrew/dive_loop_45_right_2_4.png", + "x": -24, + "y": -10, + "palette": "keep" + }, + { + "path": "track/corkscrew/dive_loop_45_right_3_1.png", + "x": 0, + "y": -30, + "palette": "keep" + }, + { + "path": "track/corkscrew/dive_loop_45_right_3_2.png", + "x": -14, + "y": -46, + "palette": "keep" + }, + { + "path": "track/corkscrew/dive_loop_45_right_3_3.png", + "x": -28, + "y": -44, + "palette": "keep" + }, + { + "path": "track/corkscrew/dive_loop_45_right_3_4.png", + "x": -24, + "y": -17, + "palette": "keep" + }, + { + "path": "track/corkscrew/dive_loop_45_right_4_1.png", + "x": -14, + "y": -32, + "palette": "keep" + }, + { + "path": "track/corkscrew/dive_loop_45_right_4_2.png", + "x": -10, + "y": -82, + "palette": "keep" + }, + { + "path": "track/corkscrew/dive_loop_45_right_4_3.png", + "x": -27, + "y": -40, + "palette": "keep" + }, + { + "path": "track/corkscrew/dive_loop_45_right_4_4.png", + "x": -21, + "y": -17, + "palette": "keep" + }, { "path": "track/lim/barrel_roll_left_1_1.png", "x": -22, @@ -35479,6 +36487,342 @@ "y": -15, "palette": "keep" }, + { + "path": "track/raptor/flat_to_steep_up_diag_1_1.png", + "x": -32, + "y": 0, + "palette": "keep" + }, + { + "path": "track/raptor/flat_to_steep_up_diag_1_2.png", + "x": -32, + "y": -20, + "palette": "keep" + }, + { + "path": "track/raptor/flat_to_steep_up_diag_1_3.png", + "x": -32, + "y": -39, + "palette": "keep" + }, + { + "path": "track/raptor/flat_to_steep_up_diag_2_1.png", + "x": -3, + "y": -6, + "palette": "keep" + }, + { + "path": "track/raptor/flat_to_steep_up_diag_2_2.png", + "x": 0, + "y": 0, + "palette": "keep" + }, + { + "path": "track/raptor/flat_to_steep_up_diag_2_3.png", + "x": -3, + "y": -22, + "palette": "keep" + }, + { + "path": "track/raptor/flat_to_steep_up_diag_3_1.png", + "x": -32, + "y": 0, + "palette": "keep" + }, + { + "path": "track/raptor/flat_to_steep_up_diag_3_2.png", + "x": -32, + "y": -20, + "palette": "keep" + }, + { + "path": "track/raptor/flat_to_steep_up_diag_3_3.png", + "x": -32, + "y": -39, + "palette": "keep" + }, + { + "path": "track/raptor/flat_to_steep_up_diag_4_1.png", + "x": -3, + "y": -16, + "palette": "keep" + }, + { + "path": "track/raptor/flat_to_steep_up_diag_4_2.png", + "x": -3, + "y": -48, + "palette": "keep" + }, + { + "path": "track/raptor/flat_to_steep_up_diag_4_3.png", + "x": -3, + "y": -85, + "palette": "keep" + }, + { + "path": "track/raptor/steep_to_flat_up_diag_1_1.png", + "x": -32, + "y": -42, + "palette": "keep" + }, + { + "path": "track/raptor/steep_to_flat_up_diag_1_2.png", + "x": -32, + "y": -14, + "palette": "keep" + }, + { + "path": "track/raptor/steep_to_flat_up_diag_1_3.png", + "x": -32, + "y": 1, + "palette": "keep" + }, + { + "path": "track/raptor/steep_to_flat_up_diag_2_1.png", + "x": 0, + "y": 0, + "palette": "keep" + }, + { + "path": "track/raptor/steep_to_flat_up_diag_2_2.png", + "x": 0, + "y": 0, + "palette": "keep" + }, + { + "path": "track/raptor/steep_to_flat_up_diag_2_3.png", + "x": -3, + "y": -10, + "palette": "keep" + }, + { + "path": "track/raptor/steep_to_flat_up_diag_3_1.png", + "x": -32, + "y": -42, + "palette": "keep" + }, + { + "path": "track/raptor/steep_to_flat_up_diag_3_2.png", + "x": -32, + "y": -14, + "palette": "keep" + }, + { + "path": "track/raptor/steep_to_flat_up_diag_3_3.png", + "x": -32, + "y": 1, + "palette": "keep" + }, + { + "path": "track/raptor/steep_to_flat_up_diag_4_1.png", + "x": -3, + "y": -32, + "palette": "keep" + }, + { + "path": "track/raptor/steep_to_flat_up_diag_4_2.png", + "x": -3, + "y": -72, + "palette": "keep" + }, + { + "path": "track/raptor/steep_to_flat_up_diag_4_3.png", + "x": -3, + "y": -37, + "palette": "keep" + }, + { + "path": "track/raptor/dive_loop_45_left_1_1.png", + "x": -32, + "y": -26, + "palette": "keep" + }, + { + "path": "track/raptor/dive_loop_45_left_1_2.png", + "x": -32, + "y": -37, + "palette": "keep" + }, + { + "path": "track/raptor/dive_loop_45_left_1_3.png", + "x": -27, + "y": -38, + "palette": "keep" + }, + { + "path": "track/raptor/dive_loop_45_left_1_4.png", + "x": -14, + "y": -13, + "palette": "keep" + }, + { + "path": "track/raptor/dive_loop_45_left_2_1.png", + "x": -3, + "y": 12, + "palette": "keep" + }, + { + "path": "track/raptor/dive_loop_45_left_2_2.png", + "x": -1, + "y": -24, + "palette": "keep" + }, + { + "path": "track/raptor/dive_loop_45_left_2_3.png", + "x": -20, + "y": -16, + "palette": "keep" + }, + { + "path": "track/raptor/dive_loop_45_left_2_4.png", + "x": -23, + "y": -4, + "palette": "keep" + }, + { + "path": "track/raptor/dive_loop_45_left_3_1.png", + "x": 0, + "y": -26, + "palette": "keep" + }, + { + "path": "track/raptor/dive_loop_45_left_3_2.png", + "x": -12, + "y": -23, + "palette": "keep" + }, + { + "path": "track/raptor/dive_loop_45_left_3_3.png", + "x": -16, + "y": -12, + "palette": "keep" + }, + { + "path": "track/raptor/dive_loop_45_left_3_4.png", + "x": -18, + "y": -3, + "palette": "keep" + }, + { + "path": "track/raptor/dive_loop_45_left_4_1.png", + "x": -7, + "y": -32, + "palette": "keep" + }, + { + "path": "track/raptor/dive_loop_45_left_4_2.png", + "x": -24, + "y": -46, + "palette": "keep" + }, + { + "path": "track/raptor/dive_loop_45_left_4_3.png", + "x": -24, + "y": -38, + "palette": "keep" + }, + { + "path": "track/raptor/dive_loop_45_left_4_4.png", + "x": -18, + "y": -13, + "palette": "keep" + }, + { + "path": "track/raptor/dive_loop_45_right_1_1.png", + "x": -32, + "y": -26, + "palette": "keep" + }, + { + "path": "track/raptor/dive_loop_45_right_1_2.png", + "x": -32, + "y": -23, + "palette": "keep" + }, + { + "path": "track/raptor/dive_loop_45_right_1_3.png", + "x": -24, + "y": -12, + "palette": "keep" + }, + { + "path": "track/raptor/dive_loop_45_right_1_4.png", + "x": -32, + "y": -3, + "palette": "keep" + }, + { + "path": "track/raptor/dive_loop_45_right_2_1.png", + "x": -5, + "y": 12, + "palette": "keep" + }, + { + "path": "track/raptor/dive_loop_45_right_2_2.png", + "x": -19, + "y": -24, + "palette": "keep" + }, + { + "path": "track/raptor/dive_loop_45_right_2_3.png", + "x": -11, + "y": -16, + "palette": "keep" + }, + { + "path": "track/raptor/dive_loop_45_right_2_4.png", + "x": -18, + "y": -4, + "palette": "keep" + }, + { + "path": "track/raptor/dive_loop_45_right_3_1.png", + "x": 0, + "y": -26, + "palette": "keep" + }, + { + "path": "track/raptor/dive_loop_45_right_3_2.png", + "x": -11, + "y": -37, + "palette": "keep" + }, + { + "path": "track/raptor/dive_loop_45_right_3_3.png", + "x": -22, + "y": -38, + "palette": "keep" + }, + { + "path": "track/raptor/dive_loop_45_right_3_4.png", + "x": -18, + "y": -13, + "palette": "keep" + }, + { + "path": "track/raptor/dive_loop_45_right_4_1.png", + "x": -3, + "y": -32, + "palette": "keep" + }, + { + "path": "track/raptor/dive_loop_45_right_4_2.png", + "x": -1, + "y": -80, + "palette": "keep" + }, + { + "path": "track/raptor/dive_loop_45_right_4_3.png", + "x": -23, + "y": -38, + "palette": "keep" + }, + { + "path": "track/raptor/dive_loop_45_right_4_4.png", + "x": -14, + "y": -13, + "palette": "keep" + }, { "path": "track/raptor/flat_lift_1.png", "x": -18, diff --git a/resources/g2/track/bm/dive_loop_45_left_1_1.png b/resources/g2/track/bm/dive_loop_45_left_1_1.png new file mode 100644 index 0000000000..79f3cbe28c Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_left_1_1.png differ diff --git a/resources/g2/track/bm/dive_loop_45_left_1_2.png b/resources/g2/track/bm/dive_loop_45_left_1_2.png new file mode 100644 index 0000000000..8859b18970 Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_left_1_2.png differ diff --git a/resources/g2/track/bm/dive_loop_45_left_1_3.png b/resources/g2/track/bm/dive_loop_45_left_1_3.png new file mode 100644 index 0000000000..9771a16644 Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_left_1_3.png differ diff --git a/resources/g2/track/bm/dive_loop_45_left_1_4.png b/resources/g2/track/bm/dive_loop_45_left_1_4.png new file mode 100644 index 0000000000..7e3a09d563 Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_left_1_4.png differ diff --git a/resources/g2/track/bm/dive_loop_45_left_2_1.png b/resources/g2/track/bm/dive_loop_45_left_2_1.png new file mode 100644 index 0000000000..54df52b812 Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_left_2_1.png differ diff --git a/resources/g2/track/bm/dive_loop_45_left_2_2.png b/resources/g2/track/bm/dive_loop_45_left_2_2.png new file mode 100644 index 0000000000..2cb8cafd64 Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_left_2_2.png differ diff --git a/resources/g2/track/bm/dive_loop_45_left_2_3.png b/resources/g2/track/bm/dive_loop_45_left_2_3.png new file mode 100644 index 0000000000..d3bf497762 Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_left_2_3.png differ diff --git a/resources/g2/track/bm/dive_loop_45_left_2_4.png b/resources/g2/track/bm/dive_loop_45_left_2_4.png new file mode 100644 index 0000000000..361d40b67d Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_left_2_4.png differ diff --git a/resources/g2/track/bm/dive_loop_45_left_3_1.png b/resources/g2/track/bm/dive_loop_45_left_3_1.png new file mode 100644 index 0000000000..b7cfb80ee4 Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_left_3_1.png differ diff --git a/resources/g2/track/bm/dive_loop_45_left_3_2.png b/resources/g2/track/bm/dive_loop_45_left_3_2.png new file mode 100644 index 0000000000..2bfc6b3957 Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_left_3_2.png differ diff --git a/resources/g2/track/bm/dive_loop_45_left_3_3.png b/resources/g2/track/bm/dive_loop_45_left_3_3.png new file mode 100644 index 0000000000..b45bd199f4 Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_left_3_3.png differ diff --git a/resources/g2/track/bm/dive_loop_45_left_3_4.png b/resources/g2/track/bm/dive_loop_45_left_3_4.png new file mode 100644 index 0000000000..67994bc37b Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_left_3_4.png differ diff --git a/resources/g2/track/bm/dive_loop_45_left_4_1.png b/resources/g2/track/bm/dive_loop_45_left_4_1.png new file mode 100644 index 0000000000..756ce82f2b Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_left_4_1.png differ diff --git a/resources/g2/track/bm/dive_loop_45_left_4_2.png b/resources/g2/track/bm/dive_loop_45_left_4_2.png new file mode 100644 index 0000000000..3628fce680 Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_left_4_2.png differ diff --git a/resources/g2/track/bm/dive_loop_45_left_4_3.png b/resources/g2/track/bm/dive_loop_45_left_4_3.png new file mode 100644 index 0000000000..df09479226 Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_left_4_3.png differ diff --git a/resources/g2/track/bm/dive_loop_45_left_4_4.png b/resources/g2/track/bm/dive_loop_45_left_4_4.png new file mode 100644 index 0000000000..578e26e77f Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_left_4_4.png differ diff --git a/resources/g2/track/bm/dive_loop_45_right_1_1.png b/resources/g2/track/bm/dive_loop_45_right_1_1.png new file mode 100644 index 0000000000..bcf98c201a Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_right_1_1.png differ diff --git a/resources/g2/track/bm/dive_loop_45_right_1_2.png b/resources/g2/track/bm/dive_loop_45_right_1_2.png new file mode 100644 index 0000000000..8403b18d43 Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_right_1_2.png differ diff --git a/resources/g2/track/bm/dive_loop_45_right_1_3.png b/resources/g2/track/bm/dive_loop_45_right_1_3.png new file mode 100644 index 0000000000..7679e76035 Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_right_1_3.png differ diff --git a/resources/g2/track/bm/dive_loop_45_right_1_4.png b/resources/g2/track/bm/dive_loop_45_right_1_4.png new file mode 100644 index 0000000000..633cfd3c55 Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_right_1_4.png differ diff --git a/resources/g2/track/bm/dive_loop_45_right_2_1.png b/resources/g2/track/bm/dive_loop_45_right_2_1.png new file mode 100644 index 0000000000..ac3cbf9c06 Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_right_2_1.png differ diff --git a/resources/g2/track/bm/dive_loop_45_right_2_2.png b/resources/g2/track/bm/dive_loop_45_right_2_2.png new file mode 100644 index 0000000000..a12088fe86 Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_right_2_2.png differ diff --git a/resources/g2/track/bm/dive_loop_45_right_2_3.png b/resources/g2/track/bm/dive_loop_45_right_2_3.png new file mode 100644 index 0000000000..a3b7c671d0 Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_right_2_3.png differ diff --git a/resources/g2/track/bm/dive_loop_45_right_2_4.png b/resources/g2/track/bm/dive_loop_45_right_2_4.png new file mode 100644 index 0000000000..18c42fd1a7 Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_right_2_4.png differ diff --git a/resources/g2/track/bm/dive_loop_45_right_3_1.png b/resources/g2/track/bm/dive_loop_45_right_3_1.png new file mode 100644 index 0000000000..053095da0e Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_right_3_1.png differ diff --git a/resources/g2/track/bm/dive_loop_45_right_3_2.png b/resources/g2/track/bm/dive_loop_45_right_3_2.png new file mode 100644 index 0000000000..a2dbc61cf7 Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_right_3_2.png differ diff --git a/resources/g2/track/bm/dive_loop_45_right_3_3.png b/resources/g2/track/bm/dive_loop_45_right_3_3.png new file mode 100644 index 0000000000..d1d342be73 Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_right_3_3.png differ diff --git a/resources/g2/track/bm/dive_loop_45_right_3_4.png b/resources/g2/track/bm/dive_loop_45_right_3_4.png new file mode 100644 index 0000000000..122ab9dffa Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_right_3_4.png differ diff --git a/resources/g2/track/bm/dive_loop_45_right_4_1.png b/resources/g2/track/bm/dive_loop_45_right_4_1.png new file mode 100644 index 0000000000..a7d9e9be5b Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_right_4_1.png differ diff --git a/resources/g2/track/bm/dive_loop_45_right_4_2.png b/resources/g2/track/bm/dive_loop_45_right_4_2.png new file mode 100644 index 0000000000..ad3a0436ff Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_right_4_2.png differ diff --git a/resources/g2/track/bm/dive_loop_45_right_4_3.png b/resources/g2/track/bm/dive_loop_45_right_4_3.png new file mode 100644 index 0000000000..c35ad2b7f4 Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_right_4_3.png differ diff --git a/resources/g2/track/bm/dive_loop_45_right_4_4.png b/resources/g2/track/bm/dive_loop_45_right_4_4.png new file mode 100644 index 0000000000..786fbcdbc5 Binary files /dev/null and b/resources/g2/track/bm/dive_loop_45_right_4_4.png differ diff --git a/resources/g2/track/bm/flat_to_steep_up_diag_1_1.png b/resources/g2/track/bm/flat_to_steep_up_diag_1_1.png new file mode 100644 index 0000000000..07a4ac05ed Binary files /dev/null and b/resources/g2/track/bm/flat_to_steep_up_diag_1_1.png differ diff --git a/resources/g2/track/bm/flat_to_steep_up_diag_1_2.png b/resources/g2/track/bm/flat_to_steep_up_diag_1_2.png new file mode 100644 index 0000000000..d7f3b0de9c Binary files /dev/null and b/resources/g2/track/bm/flat_to_steep_up_diag_1_2.png differ diff --git a/resources/g2/track/bm/flat_to_steep_up_diag_1_3.png b/resources/g2/track/bm/flat_to_steep_up_diag_1_3.png new file mode 100644 index 0000000000..c0ad64d04b Binary files /dev/null and b/resources/g2/track/bm/flat_to_steep_up_diag_1_3.png differ diff --git a/resources/g2/track/bm/flat_to_steep_up_diag_2_1.png b/resources/g2/track/bm/flat_to_steep_up_diag_2_1.png new file mode 100644 index 0000000000..43ad8945e6 Binary files /dev/null and b/resources/g2/track/bm/flat_to_steep_up_diag_2_1.png differ diff --git a/resources/g2/track/bm/flat_to_steep_up_diag_2_2.png b/resources/g2/track/bm/flat_to_steep_up_diag_2_2.png new file mode 100644 index 0000000000..251476d353 Binary files /dev/null and b/resources/g2/track/bm/flat_to_steep_up_diag_2_2.png differ diff --git a/resources/g2/track/bm/flat_to_steep_up_diag_2_3.png b/resources/g2/track/bm/flat_to_steep_up_diag_2_3.png new file mode 100644 index 0000000000..0c089d227d Binary files /dev/null and b/resources/g2/track/bm/flat_to_steep_up_diag_2_3.png differ diff --git a/resources/g2/track/bm/flat_to_steep_up_diag_3_1.png b/resources/g2/track/bm/flat_to_steep_up_diag_3_1.png new file mode 100644 index 0000000000..c4aa940153 Binary files /dev/null and b/resources/g2/track/bm/flat_to_steep_up_diag_3_1.png differ diff --git a/resources/g2/track/bm/flat_to_steep_up_diag_3_2.png b/resources/g2/track/bm/flat_to_steep_up_diag_3_2.png new file mode 100644 index 0000000000..b46e224440 Binary files /dev/null and b/resources/g2/track/bm/flat_to_steep_up_diag_3_2.png differ diff --git a/resources/g2/track/bm/flat_to_steep_up_diag_3_3.png b/resources/g2/track/bm/flat_to_steep_up_diag_3_3.png new file mode 100644 index 0000000000..425f7ea904 Binary files /dev/null and b/resources/g2/track/bm/flat_to_steep_up_diag_3_3.png differ diff --git a/resources/g2/track/bm/flat_to_steep_up_diag_4_1.png b/resources/g2/track/bm/flat_to_steep_up_diag_4_1.png new file mode 100644 index 0000000000..40f1070761 Binary files /dev/null and b/resources/g2/track/bm/flat_to_steep_up_diag_4_1.png differ diff --git a/resources/g2/track/bm/flat_to_steep_up_diag_4_2.png b/resources/g2/track/bm/flat_to_steep_up_diag_4_2.png new file mode 100644 index 0000000000..7b9b96bf82 Binary files /dev/null and b/resources/g2/track/bm/flat_to_steep_up_diag_4_2.png differ diff --git a/resources/g2/track/bm/flat_to_steep_up_diag_4_3.png b/resources/g2/track/bm/flat_to_steep_up_diag_4_3.png new file mode 100644 index 0000000000..afbe70371c Binary files /dev/null and b/resources/g2/track/bm/flat_to_steep_up_diag_4_3.png differ diff --git a/resources/g2/track/bm/steep_to_flat_up_diag_1_1.png b/resources/g2/track/bm/steep_to_flat_up_diag_1_1.png new file mode 100644 index 0000000000..59f9c84cc9 Binary files /dev/null and b/resources/g2/track/bm/steep_to_flat_up_diag_1_1.png differ diff --git a/resources/g2/track/bm/steep_to_flat_up_diag_1_2.png b/resources/g2/track/bm/steep_to_flat_up_diag_1_2.png new file mode 100644 index 0000000000..de21ddfb91 Binary files /dev/null and b/resources/g2/track/bm/steep_to_flat_up_diag_1_2.png differ diff --git a/resources/g2/track/bm/steep_to_flat_up_diag_1_3.png b/resources/g2/track/bm/steep_to_flat_up_diag_1_3.png new file mode 100644 index 0000000000..093080da19 Binary files /dev/null and b/resources/g2/track/bm/steep_to_flat_up_diag_1_3.png differ diff --git a/resources/g2/track/bm/steep_to_flat_up_diag_2_1.png b/resources/g2/track/bm/steep_to_flat_up_diag_2_1.png new file mode 100644 index 0000000000..251476d353 Binary files /dev/null and b/resources/g2/track/bm/steep_to_flat_up_diag_2_1.png differ diff --git a/resources/g2/track/bm/steep_to_flat_up_diag_2_2.png b/resources/g2/track/bm/steep_to_flat_up_diag_2_2.png new file mode 100644 index 0000000000..251476d353 Binary files /dev/null and b/resources/g2/track/bm/steep_to_flat_up_diag_2_2.png differ diff --git a/resources/g2/track/bm/steep_to_flat_up_diag_2_3.png b/resources/g2/track/bm/steep_to_flat_up_diag_2_3.png new file mode 100644 index 0000000000..3cf5dfbf46 Binary files /dev/null and b/resources/g2/track/bm/steep_to_flat_up_diag_2_3.png differ diff --git a/resources/g2/track/bm/steep_to_flat_up_diag_3_1.png b/resources/g2/track/bm/steep_to_flat_up_diag_3_1.png new file mode 100644 index 0000000000..c5812256ce Binary files /dev/null and b/resources/g2/track/bm/steep_to_flat_up_diag_3_1.png differ diff --git a/resources/g2/track/bm/steep_to_flat_up_diag_3_2.png b/resources/g2/track/bm/steep_to_flat_up_diag_3_2.png new file mode 100644 index 0000000000..1f53d098cc Binary files /dev/null and b/resources/g2/track/bm/steep_to_flat_up_diag_3_2.png differ diff --git a/resources/g2/track/bm/steep_to_flat_up_diag_3_3.png b/resources/g2/track/bm/steep_to_flat_up_diag_3_3.png new file mode 100644 index 0000000000..0c3ab55bb3 Binary files /dev/null and b/resources/g2/track/bm/steep_to_flat_up_diag_3_3.png differ diff --git a/resources/g2/track/bm/steep_to_flat_up_diag_4_1.png b/resources/g2/track/bm/steep_to_flat_up_diag_4_1.png new file mode 100644 index 0000000000..a24caad65b Binary files /dev/null and b/resources/g2/track/bm/steep_to_flat_up_diag_4_1.png differ diff --git a/resources/g2/track/bm/steep_to_flat_up_diag_4_2.png b/resources/g2/track/bm/steep_to_flat_up_diag_4_2.png new file mode 100644 index 0000000000..19a700bfdf Binary files /dev/null and b/resources/g2/track/bm/steep_to_flat_up_diag_4_2.png differ diff --git a/resources/g2/track/bm/steep_to_flat_up_diag_4_3.png b/resources/g2/track/bm/steep_to_flat_up_diag_4_3.png new file mode 100644 index 0000000000..4136a1e253 Binary files /dev/null and b/resources/g2/track/bm/steep_to_flat_up_diag_4_3.png differ diff --git a/resources/g2/track/corkscrew/dive_loop_45_left_1_1.png b/resources/g2/track/corkscrew/dive_loop_45_left_1_1.png new file mode 100644 index 0000000000..8cb5ff2ef5 Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_left_1_1.png differ diff --git a/resources/g2/track/corkscrew/dive_loop_45_left_1_2.png b/resources/g2/track/corkscrew/dive_loop_45_left_1_2.png new file mode 100644 index 0000000000..0e2391b7a9 Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_left_1_2.png differ diff --git a/resources/g2/track/corkscrew/dive_loop_45_left_1_3.png b/resources/g2/track/corkscrew/dive_loop_45_left_1_3.png new file mode 100644 index 0000000000..af3bf6b616 Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_left_1_3.png differ diff --git a/resources/g2/track/corkscrew/dive_loop_45_left_1_4.png b/resources/g2/track/corkscrew/dive_loop_45_left_1_4.png new file mode 100644 index 0000000000..45ffb1e032 Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_left_1_4.png differ diff --git a/resources/g2/track/corkscrew/dive_loop_45_left_2_1.png b/resources/g2/track/corkscrew/dive_loop_45_left_2_1.png new file mode 100644 index 0000000000..6625048328 Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_left_2_1.png differ diff --git a/resources/g2/track/corkscrew/dive_loop_45_left_2_2.png b/resources/g2/track/corkscrew/dive_loop_45_left_2_2.png new file mode 100644 index 0000000000..5dcb878c5e Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_left_2_2.png differ diff --git a/resources/g2/track/corkscrew/dive_loop_45_left_2_3.png b/resources/g2/track/corkscrew/dive_loop_45_left_2_3.png new file mode 100644 index 0000000000..aba3d35f88 Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_left_2_3.png differ diff --git a/resources/g2/track/corkscrew/dive_loop_45_left_2_4.png b/resources/g2/track/corkscrew/dive_loop_45_left_2_4.png new file mode 100644 index 0000000000..ccfa253960 Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_left_2_4.png differ diff --git a/resources/g2/track/corkscrew/dive_loop_45_left_3_1.png b/resources/g2/track/corkscrew/dive_loop_45_left_3_1.png new file mode 100644 index 0000000000..612d1f22df Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_left_3_1.png differ diff --git a/resources/g2/track/corkscrew/dive_loop_45_left_3_2.png b/resources/g2/track/corkscrew/dive_loop_45_left_3_2.png new file mode 100644 index 0000000000..803a116aa9 Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_left_3_2.png differ diff --git a/resources/g2/track/corkscrew/dive_loop_45_left_3_3.png b/resources/g2/track/corkscrew/dive_loop_45_left_3_3.png new file mode 100644 index 0000000000..c04d7b2576 Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_left_3_3.png differ diff --git a/resources/g2/track/corkscrew/dive_loop_45_left_3_4.png b/resources/g2/track/corkscrew/dive_loop_45_left_3_4.png new file mode 100644 index 0000000000..f1c32079a2 Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_left_3_4.png differ diff --git a/resources/g2/track/corkscrew/dive_loop_45_left_4_1.png b/resources/g2/track/corkscrew/dive_loop_45_left_4_1.png new file mode 100644 index 0000000000..1a3dc4d0d7 Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_left_4_1.png differ diff --git a/resources/g2/track/corkscrew/dive_loop_45_left_4_2.png b/resources/g2/track/corkscrew/dive_loop_45_left_4_2.png new file mode 100644 index 0000000000..250848444f Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_left_4_2.png differ diff --git a/resources/g2/track/corkscrew/dive_loop_45_left_4_3.png b/resources/g2/track/corkscrew/dive_loop_45_left_4_3.png new file mode 100644 index 0000000000..aa78cfc363 Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_left_4_3.png differ diff --git a/resources/g2/track/corkscrew/dive_loop_45_left_4_4.png b/resources/g2/track/corkscrew/dive_loop_45_left_4_4.png new file mode 100644 index 0000000000..7d26dd6729 Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_left_4_4.png differ diff --git a/resources/g2/track/corkscrew/dive_loop_45_right_1_1.png b/resources/g2/track/corkscrew/dive_loop_45_right_1_1.png new file mode 100644 index 0000000000..445b0bb646 Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_right_1_1.png differ diff --git a/resources/g2/track/corkscrew/dive_loop_45_right_1_2.png b/resources/g2/track/corkscrew/dive_loop_45_right_1_2.png new file mode 100644 index 0000000000..815a430ded Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_right_1_2.png differ diff --git a/resources/g2/track/corkscrew/dive_loop_45_right_1_3.png b/resources/g2/track/corkscrew/dive_loop_45_right_1_3.png new file mode 100644 index 0000000000..2622af83ff Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_right_1_3.png differ diff --git a/resources/g2/track/corkscrew/dive_loop_45_right_1_4.png b/resources/g2/track/corkscrew/dive_loop_45_right_1_4.png new file mode 100644 index 0000000000..1bfff83e6c Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_right_1_4.png differ diff --git a/resources/g2/track/corkscrew/dive_loop_45_right_2_1.png b/resources/g2/track/corkscrew/dive_loop_45_right_2_1.png new file mode 100644 index 0000000000..e315319b6a Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_right_2_1.png differ diff --git a/resources/g2/track/corkscrew/dive_loop_45_right_2_2.png b/resources/g2/track/corkscrew/dive_loop_45_right_2_2.png new file mode 100644 index 0000000000..d7d8c5cd83 Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_right_2_2.png differ diff --git a/resources/g2/track/corkscrew/dive_loop_45_right_2_3.png b/resources/g2/track/corkscrew/dive_loop_45_right_2_3.png new file mode 100644 index 0000000000..71ea002df3 Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_right_2_3.png differ diff --git a/resources/g2/track/corkscrew/dive_loop_45_right_2_4.png b/resources/g2/track/corkscrew/dive_loop_45_right_2_4.png new file mode 100644 index 0000000000..85981cc046 Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_right_2_4.png differ diff --git a/resources/g2/track/corkscrew/dive_loop_45_right_3_1.png b/resources/g2/track/corkscrew/dive_loop_45_right_3_1.png new file mode 100644 index 0000000000..5215a11f80 Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_right_3_1.png differ diff --git a/resources/g2/track/corkscrew/dive_loop_45_right_3_2.png b/resources/g2/track/corkscrew/dive_loop_45_right_3_2.png new file mode 100644 index 0000000000..97aa99080f Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_right_3_2.png differ diff --git a/resources/g2/track/corkscrew/dive_loop_45_right_3_3.png b/resources/g2/track/corkscrew/dive_loop_45_right_3_3.png new file mode 100644 index 0000000000..e31fec77d1 Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_right_3_3.png differ diff --git a/resources/g2/track/corkscrew/dive_loop_45_right_3_4.png b/resources/g2/track/corkscrew/dive_loop_45_right_3_4.png new file mode 100644 index 0000000000..f492fbd7f8 Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_right_3_4.png differ diff --git a/resources/g2/track/corkscrew/dive_loop_45_right_4_1.png b/resources/g2/track/corkscrew/dive_loop_45_right_4_1.png new file mode 100644 index 0000000000..5c98c16bee Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_right_4_1.png differ diff --git a/resources/g2/track/corkscrew/dive_loop_45_right_4_2.png b/resources/g2/track/corkscrew/dive_loop_45_right_4_2.png new file mode 100644 index 0000000000..0c58e41a72 Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_right_4_2.png differ diff --git a/resources/g2/track/corkscrew/dive_loop_45_right_4_3.png b/resources/g2/track/corkscrew/dive_loop_45_right_4_3.png new file mode 100644 index 0000000000..553f56cadd Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_right_4_3.png differ diff --git a/resources/g2/track/corkscrew/dive_loop_45_right_4_4.png b/resources/g2/track/corkscrew/dive_loop_45_right_4_4.png new file mode 100644 index 0000000000..43d6268eaa Binary files /dev/null and b/resources/g2/track/corkscrew/dive_loop_45_right_4_4.png differ diff --git a/resources/g2/track/corkscrew/flat_to_steep_up_diag_1_1.png b/resources/g2/track/corkscrew/flat_to_steep_up_diag_1_1.png new file mode 100644 index 0000000000..561925a0d3 Binary files /dev/null and b/resources/g2/track/corkscrew/flat_to_steep_up_diag_1_1.png differ diff --git a/resources/g2/track/corkscrew/flat_to_steep_up_diag_1_2.png b/resources/g2/track/corkscrew/flat_to_steep_up_diag_1_2.png new file mode 100644 index 0000000000..176eb715e6 Binary files /dev/null and b/resources/g2/track/corkscrew/flat_to_steep_up_diag_1_2.png differ diff --git a/resources/g2/track/corkscrew/flat_to_steep_up_diag_1_3.png b/resources/g2/track/corkscrew/flat_to_steep_up_diag_1_3.png new file mode 100644 index 0000000000..541356ccd9 Binary files /dev/null and b/resources/g2/track/corkscrew/flat_to_steep_up_diag_1_3.png differ diff --git a/resources/g2/track/corkscrew/flat_to_steep_up_diag_2_1.png b/resources/g2/track/corkscrew/flat_to_steep_up_diag_2_1.png new file mode 100644 index 0000000000..b6b6198aa5 Binary files /dev/null and b/resources/g2/track/corkscrew/flat_to_steep_up_diag_2_1.png differ diff --git a/resources/g2/track/corkscrew/flat_to_steep_up_diag_2_2.png b/resources/g2/track/corkscrew/flat_to_steep_up_diag_2_2.png new file mode 100644 index 0000000000..251476d353 Binary files /dev/null and b/resources/g2/track/corkscrew/flat_to_steep_up_diag_2_2.png differ diff --git a/resources/g2/track/corkscrew/flat_to_steep_up_diag_2_3.png b/resources/g2/track/corkscrew/flat_to_steep_up_diag_2_3.png new file mode 100644 index 0000000000..bc433a3f14 Binary files /dev/null and b/resources/g2/track/corkscrew/flat_to_steep_up_diag_2_3.png differ diff --git a/resources/g2/track/corkscrew/flat_to_steep_up_diag_3_1.png b/resources/g2/track/corkscrew/flat_to_steep_up_diag_3_1.png new file mode 100644 index 0000000000..6b6b25fdb2 Binary files /dev/null and b/resources/g2/track/corkscrew/flat_to_steep_up_diag_3_1.png differ diff --git a/resources/g2/track/corkscrew/flat_to_steep_up_diag_3_2.png b/resources/g2/track/corkscrew/flat_to_steep_up_diag_3_2.png new file mode 100644 index 0000000000..ee37da31e1 Binary files /dev/null and b/resources/g2/track/corkscrew/flat_to_steep_up_diag_3_2.png differ diff --git a/resources/g2/track/corkscrew/flat_to_steep_up_diag_3_3.png b/resources/g2/track/corkscrew/flat_to_steep_up_diag_3_3.png new file mode 100644 index 0000000000..4deb0d906b Binary files /dev/null and b/resources/g2/track/corkscrew/flat_to_steep_up_diag_3_3.png differ diff --git a/resources/g2/track/corkscrew/flat_to_steep_up_diag_4_1.png b/resources/g2/track/corkscrew/flat_to_steep_up_diag_4_1.png new file mode 100644 index 0000000000..a41f1609f9 Binary files /dev/null and b/resources/g2/track/corkscrew/flat_to_steep_up_diag_4_1.png differ diff --git a/resources/g2/track/corkscrew/flat_to_steep_up_diag_4_2.png b/resources/g2/track/corkscrew/flat_to_steep_up_diag_4_2.png new file mode 100644 index 0000000000..2faff9e99e Binary files /dev/null and b/resources/g2/track/corkscrew/flat_to_steep_up_diag_4_2.png differ diff --git a/resources/g2/track/corkscrew/flat_to_steep_up_diag_4_3.png b/resources/g2/track/corkscrew/flat_to_steep_up_diag_4_3.png new file mode 100644 index 0000000000..1cbc517eb4 Binary files /dev/null and b/resources/g2/track/corkscrew/flat_to_steep_up_diag_4_3.png differ diff --git a/resources/g2/track/corkscrew/steep_to_flat_up_diag_1_1.png b/resources/g2/track/corkscrew/steep_to_flat_up_diag_1_1.png new file mode 100644 index 0000000000..1623eae794 Binary files /dev/null and b/resources/g2/track/corkscrew/steep_to_flat_up_diag_1_1.png differ diff --git a/resources/g2/track/corkscrew/steep_to_flat_up_diag_1_2.png b/resources/g2/track/corkscrew/steep_to_flat_up_diag_1_2.png new file mode 100644 index 0000000000..988fe0305a Binary files /dev/null and b/resources/g2/track/corkscrew/steep_to_flat_up_diag_1_2.png differ diff --git a/resources/g2/track/corkscrew/steep_to_flat_up_diag_1_3.png b/resources/g2/track/corkscrew/steep_to_flat_up_diag_1_3.png new file mode 100644 index 0000000000..fa3c5cf89c Binary files /dev/null and b/resources/g2/track/corkscrew/steep_to_flat_up_diag_1_3.png differ diff --git a/resources/g2/track/corkscrew/steep_to_flat_up_diag_2_1.png b/resources/g2/track/corkscrew/steep_to_flat_up_diag_2_1.png new file mode 100644 index 0000000000..251476d353 Binary files /dev/null and b/resources/g2/track/corkscrew/steep_to_flat_up_diag_2_1.png differ diff --git a/resources/g2/track/corkscrew/steep_to_flat_up_diag_2_2.png b/resources/g2/track/corkscrew/steep_to_flat_up_diag_2_2.png new file mode 100644 index 0000000000..251476d353 Binary files /dev/null and b/resources/g2/track/corkscrew/steep_to_flat_up_diag_2_2.png differ diff --git a/resources/g2/track/corkscrew/steep_to_flat_up_diag_2_3.png b/resources/g2/track/corkscrew/steep_to_flat_up_diag_2_3.png new file mode 100644 index 0000000000..a067ad3ab1 Binary files /dev/null and b/resources/g2/track/corkscrew/steep_to_flat_up_diag_2_3.png differ diff --git a/resources/g2/track/corkscrew/steep_to_flat_up_diag_3_1.png b/resources/g2/track/corkscrew/steep_to_flat_up_diag_3_1.png new file mode 100644 index 0000000000..7fc02542b0 Binary files /dev/null and b/resources/g2/track/corkscrew/steep_to_flat_up_diag_3_1.png differ diff --git a/resources/g2/track/corkscrew/steep_to_flat_up_diag_3_2.png b/resources/g2/track/corkscrew/steep_to_flat_up_diag_3_2.png new file mode 100644 index 0000000000..c14b9af2cf Binary files /dev/null and b/resources/g2/track/corkscrew/steep_to_flat_up_diag_3_2.png differ diff --git a/resources/g2/track/corkscrew/steep_to_flat_up_diag_3_3.png b/resources/g2/track/corkscrew/steep_to_flat_up_diag_3_3.png new file mode 100644 index 0000000000..ee64cfc951 Binary files /dev/null and b/resources/g2/track/corkscrew/steep_to_flat_up_diag_3_3.png differ diff --git a/resources/g2/track/corkscrew/steep_to_flat_up_diag_4_1.png b/resources/g2/track/corkscrew/steep_to_flat_up_diag_4_1.png new file mode 100644 index 0000000000..470d05a186 Binary files /dev/null and b/resources/g2/track/corkscrew/steep_to_flat_up_diag_4_1.png differ diff --git a/resources/g2/track/corkscrew/steep_to_flat_up_diag_4_2.png b/resources/g2/track/corkscrew/steep_to_flat_up_diag_4_2.png new file mode 100644 index 0000000000..7799b7031e Binary files /dev/null and b/resources/g2/track/corkscrew/steep_to_flat_up_diag_4_2.png differ diff --git a/resources/g2/track/corkscrew/steep_to_flat_up_diag_4_3.png b/resources/g2/track/corkscrew/steep_to_flat_up_diag_4_3.png new file mode 100644 index 0000000000..f477d80e44 Binary files /dev/null and b/resources/g2/track/corkscrew/steep_to_flat_up_diag_4_3.png differ diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_left_1_1.png b/resources/g2/track/lattice_triangle/dive_loop_45_left_1_1.png new file mode 100644 index 0000000000..8f478d8ef6 Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_left_1_1.png differ diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_left_1_2.png b/resources/g2/track/lattice_triangle/dive_loop_45_left_1_2.png new file mode 100644 index 0000000000..aa24fdf9b5 Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_left_1_2.png differ diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_left_1_3.png b/resources/g2/track/lattice_triangle/dive_loop_45_left_1_3.png new file mode 100644 index 0000000000..1c684f2260 Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_left_1_3.png differ diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_left_1_4.png b/resources/g2/track/lattice_triangle/dive_loop_45_left_1_4.png new file mode 100644 index 0000000000..f8a81dd2e5 Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_left_1_4.png differ diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_left_2_1.png b/resources/g2/track/lattice_triangle/dive_loop_45_left_2_1.png new file mode 100644 index 0000000000..97f8ef0234 Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_left_2_1.png differ diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_left_2_2.png b/resources/g2/track/lattice_triangle/dive_loop_45_left_2_2.png new file mode 100644 index 0000000000..42264ab4a3 Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_left_2_2.png differ diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_left_2_3.png b/resources/g2/track/lattice_triangle/dive_loop_45_left_2_3.png new file mode 100644 index 0000000000..df3f24391a Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_left_2_3.png differ diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_left_2_4.png b/resources/g2/track/lattice_triangle/dive_loop_45_left_2_4.png new file mode 100644 index 0000000000..b035c0167a Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_left_2_4.png differ diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_left_3_1.png b/resources/g2/track/lattice_triangle/dive_loop_45_left_3_1.png new file mode 100644 index 0000000000..e4f8f78fe7 Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_left_3_1.png differ diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_left_3_2.png b/resources/g2/track/lattice_triangle/dive_loop_45_left_3_2.png new file mode 100644 index 0000000000..a8eef697af Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_left_3_2.png differ diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_left_3_3.png b/resources/g2/track/lattice_triangle/dive_loop_45_left_3_3.png new file mode 100644 index 0000000000..c03c8c6dc6 Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_left_3_3.png differ diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_left_3_4.png b/resources/g2/track/lattice_triangle/dive_loop_45_left_3_4.png new file mode 100644 index 0000000000..2977332e8c Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_left_3_4.png differ diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_left_4_1.png b/resources/g2/track/lattice_triangle/dive_loop_45_left_4_1.png new file mode 100644 index 0000000000..a1d06ce79d Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_left_4_1.png differ diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_left_4_2.png b/resources/g2/track/lattice_triangle/dive_loop_45_left_4_2.png new file mode 100644 index 0000000000..d464f23ca1 Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_left_4_2.png differ diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_left_4_3.png b/resources/g2/track/lattice_triangle/dive_loop_45_left_4_3.png new file mode 100644 index 0000000000..8ae8b59d8e Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_left_4_3.png differ diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_left_4_4.png b/resources/g2/track/lattice_triangle/dive_loop_45_left_4_4.png new file mode 100644 index 0000000000..75f652c5f1 Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_left_4_4.png differ diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_right_1_1.png b/resources/g2/track/lattice_triangle/dive_loop_45_right_1_1.png new file mode 100644 index 0000000000..4ca2ebb0d7 Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_right_1_1.png differ diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_right_1_2.png b/resources/g2/track/lattice_triangle/dive_loop_45_right_1_2.png new file mode 100644 index 0000000000..72c3c7da5c Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_right_1_2.png differ diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_right_1_3.png b/resources/g2/track/lattice_triangle/dive_loop_45_right_1_3.png new file mode 100644 index 0000000000..60de80df48 Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_right_1_3.png differ diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_right_1_4.png b/resources/g2/track/lattice_triangle/dive_loop_45_right_1_4.png new file mode 100644 index 0000000000..a2e1a7cbe6 Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_right_1_4.png differ diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_right_2_1.png b/resources/g2/track/lattice_triangle/dive_loop_45_right_2_1.png new file mode 100644 index 0000000000..4a0e3770aa Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_right_2_1.png differ diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_right_2_2.png b/resources/g2/track/lattice_triangle/dive_loop_45_right_2_2.png new file mode 100644 index 0000000000..4e00758aeb Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_right_2_2.png differ diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_right_2_3.png b/resources/g2/track/lattice_triangle/dive_loop_45_right_2_3.png new file mode 100644 index 0000000000..ede5b32f5e Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_right_2_3.png differ diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_right_2_4.png b/resources/g2/track/lattice_triangle/dive_loop_45_right_2_4.png new file mode 100644 index 0000000000..ad075d87fc Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_right_2_4.png differ diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_right_3_1.png b/resources/g2/track/lattice_triangle/dive_loop_45_right_3_1.png new file mode 100644 index 0000000000..885e484993 Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_right_3_1.png differ diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_right_3_2.png b/resources/g2/track/lattice_triangle/dive_loop_45_right_3_2.png new file mode 100644 index 0000000000..8bb2351a92 Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_right_3_2.png differ diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_right_3_3.png b/resources/g2/track/lattice_triangle/dive_loop_45_right_3_3.png new file mode 100644 index 0000000000..9554ebd3da Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_right_3_3.png differ diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_right_3_4.png b/resources/g2/track/lattice_triangle/dive_loop_45_right_3_4.png new file mode 100644 index 0000000000..fe27833ff3 Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_right_3_4.png differ diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_right_4_1.png b/resources/g2/track/lattice_triangle/dive_loop_45_right_4_1.png new file mode 100644 index 0000000000..f12d14010f Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_right_4_1.png differ diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_right_4_2.png b/resources/g2/track/lattice_triangle/dive_loop_45_right_4_2.png new file mode 100644 index 0000000000..d7e1a292de Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_right_4_2.png differ diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_right_4_3.png b/resources/g2/track/lattice_triangle/dive_loop_45_right_4_3.png new file mode 100644 index 0000000000..d2359800f7 Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_right_4_3.png differ diff --git a/resources/g2/track/lattice_triangle/dive_loop_45_right_4_4.png b/resources/g2/track/lattice_triangle/dive_loop_45_right_4_4.png new file mode 100644 index 0000000000..f36c597135 Binary files /dev/null and b/resources/g2/track/lattice_triangle/dive_loop_45_right_4_4.png differ diff --git a/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_1.png b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_1.png new file mode 100644 index 0000000000..2baabe084f Binary files /dev/null and b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_1.png differ diff --git a/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_1_1.png b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_1_1.png new file mode 100644 index 0000000000..d669dd9f97 Binary files /dev/null and b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_1_1.png differ diff --git a/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_1_2.png b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_1_2.png new file mode 100644 index 0000000000..1b3643c62d Binary files /dev/null and b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_1_2.png differ diff --git a/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_1_3.png b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_1_3.png new file mode 100644 index 0000000000..3f5b5456fe Binary files /dev/null and b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_1_3.png differ diff --git a/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_2.png b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_2.png new file mode 100644 index 0000000000..0ba5517dfc Binary files /dev/null and b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_2.png differ diff --git a/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_2_1.png b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_2_1.png new file mode 100644 index 0000000000..463e2bfc6d Binary files /dev/null and b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_2_1.png differ diff --git a/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_2_2.png b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_2_2.png new file mode 100644 index 0000000000..251476d353 Binary files /dev/null and b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_2_2.png differ diff --git a/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_2_3.png b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_2_3.png new file mode 100644 index 0000000000..e9e5ab4309 Binary files /dev/null and b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_2_3.png differ diff --git a/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_3.png b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_3.png new file mode 100644 index 0000000000..4010677473 Binary files /dev/null and b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_3.png differ diff --git a/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_3_1.png b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_3_1.png new file mode 100644 index 0000000000..0ba55b01cb Binary files /dev/null and b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_3_1.png differ diff --git a/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_3_2.png b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_3_2.png new file mode 100644 index 0000000000..614d2f09e8 Binary files /dev/null and b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_3_2.png differ diff --git a/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_3_3.png b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_3_3.png new file mode 100644 index 0000000000..5b93eac8cb Binary files /dev/null and b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_3_3.png differ diff --git a/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_4.png b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_4.png new file mode 100644 index 0000000000..c2e8c0ec08 Binary files /dev/null and b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_4.png differ diff --git a/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_4_1.png b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_4_1.png new file mode 100644 index 0000000000..38cdae0ad1 Binary files /dev/null and b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_4_1.png differ diff --git a/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_4_2.png b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_4_2.png new file mode 100644 index 0000000000..3e7a847eef Binary files /dev/null and b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_4_2.png differ diff --git a/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_4_3.png b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_4_3.png new file mode 100644 index 0000000000..3fbe6d2fdc Binary files /dev/null and b/resources/g2/track/lattice_triangle/flat_to_steep_up_diag_4_3.png differ diff --git a/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_1.png b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_1.png new file mode 100644 index 0000000000..9d9a5293b3 Binary files /dev/null and b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_1.png differ diff --git a/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_1_1.png b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_1_1.png new file mode 100644 index 0000000000..d8b6a5e1ed Binary files /dev/null and b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_1_1.png differ diff --git a/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_1_2.png b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_1_2.png new file mode 100644 index 0000000000..794989b338 Binary files /dev/null and b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_1_2.png differ diff --git a/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_1_3.png b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_1_3.png new file mode 100644 index 0000000000..008b824b96 Binary files /dev/null and b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_1_3.png differ diff --git a/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_2.png b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_2.png new file mode 100644 index 0000000000..89adb42c83 Binary files /dev/null and b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_2.png differ diff --git a/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_2_1.png b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_2_1.png new file mode 100644 index 0000000000..251476d353 Binary files /dev/null and b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_2_1.png differ diff --git a/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_2_2.png b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_2_2.png new file mode 100644 index 0000000000..251476d353 Binary files /dev/null and b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_2_2.png differ diff --git a/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_2_3.png b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_2_3.png new file mode 100644 index 0000000000..65e0af16ce Binary files /dev/null and b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_2_3.png differ diff --git a/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_3.png b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_3.png new file mode 100644 index 0000000000..902291d2d1 Binary files /dev/null and b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_3.png differ diff --git a/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_3_1.png b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_3_1.png new file mode 100644 index 0000000000..5ee268aa98 Binary files /dev/null and b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_3_1.png differ diff --git a/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_3_2.png b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_3_2.png new file mode 100644 index 0000000000..74fe35a864 Binary files /dev/null and b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_3_2.png differ diff --git a/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_3_3.png b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_3_3.png new file mode 100644 index 0000000000..aa5ab044ca Binary files /dev/null and b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_3_3.png differ diff --git a/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_4.png b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_4.png new file mode 100644 index 0000000000..25ef9abfc1 Binary files /dev/null and b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_4.png differ diff --git a/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_4_1.png b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_4_1.png new file mode 100644 index 0000000000..0565b4a0f8 Binary files /dev/null and b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_4_1.png differ diff --git a/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_4_2.png b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_4_2.png new file mode 100644 index 0000000000..03774bfe05 Binary files /dev/null and b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_4_2.png differ diff --git a/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_4_3.png b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_4_3.png new file mode 100644 index 0000000000..f86d6d448e Binary files /dev/null and b/resources/g2/track/lattice_triangle/steep_to_flat_up_diag_4_3.png differ diff --git a/resources/g2/track/raptor/dive_loop_45_left_1_1.png b/resources/g2/track/raptor/dive_loop_45_left_1_1.png new file mode 100644 index 0000000000..5d2f718d29 Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_left_1_1.png differ diff --git a/resources/g2/track/raptor/dive_loop_45_left_1_2.png b/resources/g2/track/raptor/dive_loop_45_left_1_2.png new file mode 100644 index 0000000000..484709162c Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_left_1_2.png differ diff --git a/resources/g2/track/raptor/dive_loop_45_left_1_3.png b/resources/g2/track/raptor/dive_loop_45_left_1_3.png new file mode 100644 index 0000000000..9bb92939ff Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_left_1_3.png differ diff --git a/resources/g2/track/raptor/dive_loop_45_left_1_4.png b/resources/g2/track/raptor/dive_loop_45_left_1_4.png new file mode 100644 index 0000000000..0e11cee76e Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_left_1_4.png differ diff --git a/resources/g2/track/raptor/dive_loop_45_left_2_1.png b/resources/g2/track/raptor/dive_loop_45_left_2_1.png new file mode 100644 index 0000000000..4a0e419411 Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_left_2_1.png differ diff --git a/resources/g2/track/raptor/dive_loop_45_left_2_2.png b/resources/g2/track/raptor/dive_loop_45_left_2_2.png new file mode 100644 index 0000000000..02e1c54b82 Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_left_2_2.png differ diff --git a/resources/g2/track/raptor/dive_loop_45_left_2_3.png b/resources/g2/track/raptor/dive_loop_45_left_2_3.png new file mode 100644 index 0000000000..6519f9d6a9 Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_left_2_3.png differ diff --git a/resources/g2/track/raptor/dive_loop_45_left_2_4.png b/resources/g2/track/raptor/dive_loop_45_left_2_4.png new file mode 100644 index 0000000000..3db7ea3e7c Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_left_2_4.png differ diff --git a/resources/g2/track/raptor/dive_loop_45_left_3_1.png b/resources/g2/track/raptor/dive_loop_45_left_3_1.png new file mode 100644 index 0000000000..7e7cfdc974 Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_left_3_1.png differ diff --git a/resources/g2/track/raptor/dive_loop_45_left_3_2.png b/resources/g2/track/raptor/dive_loop_45_left_3_2.png new file mode 100644 index 0000000000..4d8b636b46 Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_left_3_2.png differ diff --git a/resources/g2/track/raptor/dive_loop_45_left_3_3.png b/resources/g2/track/raptor/dive_loop_45_left_3_3.png new file mode 100644 index 0000000000..1f6f884952 Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_left_3_3.png differ diff --git a/resources/g2/track/raptor/dive_loop_45_left_3_4.png b/resources/g2/track/raptor/dive_loop_45_left_3_4.png new file mode 100644 index 0000000000..5de1d63638 Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_left_3_4.png differ diff --git a/resources/g2/track/raptor/dive_loop_45_left_4_1.png b/resources/g2/track/raptor/dive_loop_45_left_4_1.png new file mode 100644 index 0000000000..abc870d056 Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_left_4_1.png differ diff --git a/resources/g2/track/raptor/dive_loop_45_left_4_2.png b/resources/g2/track/raptor/dive_loop_45_left_4_2.png new file mode 100644 index 0000000000..cbd0950af1 Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_left_4_2.png differ diff --git a/resources/g2/track/raptor/dive_loop_45_left_4_3.png b/resources/g2/track/raptor/dive_loop_45_left_4_3.png new file mode 100644 index 0000000000..06dc35064f Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_left_4_3.png differ diff --git a/resources/g2/track/raptor/dive_loop_45_left_4_4.png b/resources/g2/track/raptor/dive_loop_45_left_4_4.png new file mode 100644 index 0000000000..3054197c87 Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_left_4_4.png differ diff --git a/resources/g2/track/raptor/dive_loop_45_right_1_1.png b/resources/g2/track/raptor/dive_loop_45_right_1_1.png new file mode 100644 index 0000000000..6b5fa23877 Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_right_1_1.png differ diff --git a/resources/g2/track/raptor/dive_loop_45_right_1_2.png b/resources/g2/track/raptor/dive_loop_45_right_1_2.png new file mode 100644 index 0000000000..6ebae3dff6 Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_right_1_2.png differ diff --git a/resources/g2/track/raptor/dive_loop_45_right_1_3.png b/resources/g2/track/raptor/dive_loop_45_right_1_3.png new file mode 100644 index 0000000000..138b7647bc Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_right_1_3.png differ diff --git a/resources/g2/track/raptor/dive_loop_45_right_1_4.png b/resources/g2/track/raptor/dive_loop_45_right_1_4.png new file mode 100644 index 0000000000..5cdf7ef0be Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_right_1_4.png differ diff --git a/resources/g2/track/raptor/dive_loop_45_right_2_1.png b/resources/g2/track/raptor/dive_loop_45_right_2_1.png new file mode 100644 index 0000000000..cb3af11960 Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_right_2_1.png differ diff --git a/resources/g2/track/raptor/dive_loop_45_right_2_2.png b/resources/g2/track/raptor/dive_loop_45_right_2_2.png new file mode 100644 index 0000000000..c46bbdea77 Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_right_2_2.png differ diff --git a/resources/g2/track/raptor/dive_loop_45_right_2_3.png b/resources/g2/track/raptor/dive_loop_45_right_2_3.png new file mode 100644 index 0000000000..09dccfb770 Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_right_2_3.png differ diff --git a/resources/g2/track/raptor/dive_loop_45_right_2_4.png b/resources/g2/track/raptor/dive_loop_45_right_2_4.png new file mode 100644 index 0000000000..d9eeeb4957 Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_right_2_4.png differ diff --git a/resources/g2/track/raptor/dive_loop_45_right_3_1.png b/resources/g2/track/raptor/dive_loop_45_right_3_1.png new file mode 100644 index 0000000000..6821ff11d0 Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_right_3_1.png differ diff --git a/resources/g2/track/raptor/dive_loop_45_right_3_2.png b/resources/g2/track/raptor/dive_loop_45_right_3_2.png new file mode 100644 index 0000000000..4c5493434b Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_right_3_2.png differ diff --git a/resources/g2/track/raptor/dive_loop_45_right_3_3.png b/resources/g2/track/raptor/dive_loop_45_right_3_3.png new file mode 100644 index 0000000000..13a4d7fd7e Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_right_3_3.png differ diff --git a/resources/g2/track/raptor/dive_loop_45_right_3_4.png b/resources/g2/track/raptor/dive_loop_45_right_3_4.png new file mode 100644 index 0000000000..5fa7251e3a Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_right_3_4.png differ diff --git a/resources/g2/track/raptor/dive_loop_45_right_4_1.png b/resources/g2/track/raptor/dive_loop_45_right_4_1.png new file mode 100644 index 0000000000..cea656296e Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_right_4_1.png differ diff --git a/resources/g2/track/raptor/dive_loop_45_right_4_2.png b/resources/g2/track/raptor/dive_loop_45_right_4_2.png new file mode 100644 index 0000000000..8898578c76 Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_right_4_2.png differ diff --git a/resources/g2/track/raptor/dive_loop_45_right_4_3.png b/resources/g2/track/raptor/dive_loop_45_right_4_3.png new file mode 100644 index 0000000000..8a834884b8 Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_right_4_3.png differ diff --git a/resources/g2/track/raptor/dive_loop_45_right_4_4.png b/resources/g2/track/raptor/dive_loop_45_right_4_4.png new file mode 100644 index 0000000000..75608f1f57 Binary files /dev/null and b/resources/g2/track/raptor/dive_loop_45_right_4_4.png differ diff --git a/resources/g2/track/raptor/flat_to_steep_up_diag_1_1.png b/resources/g2/track/raptor/flat_to_steep_up_diag_1_1.png new file mode 100644 index 0000000000..ff14b77d7a Binary files /dev/null and b/resources/g2/track/raptor/flat_to_steep_up_diag_1_1.png differ diff --git a/resources/g2/track/raptor/flat_to_steep_up_diag_1_2.png b/resources/g2/track/raptor/flat_to_steep_up_diag_1_2.png new file mode 100644 index 0000000000..f7e40fe3f9 Binary files /dev/null and b/resources/g2/track/raptor/flat_to_steep_up_diag_1_2.png differ diff --git a/resources/g2/track/raptor/flat_to_steep_up_diag_1_3.png b/resources/g2/track/raptor/flat_to_steep_up_diag_1_3.png new file mode 100644 index 0000000000..3c78b4c5ba Binary files /dev/null and b/resources/g2/track/raptor/flat_to_steep_up_diag_1_3.png differ diff --git a/resources/g2/track/raptor/flat_to_steep_up_diag_2_1.png b/resources/g2/track/raptor/flat_to_steep_up_diag_2_1.png new file mode 100644 index 0000000000..3da2ad8e69 Binary files /dev/null and b/resources/g2/track/raptor/flat_to_steep_up_diag_2_1.png differ diff --git a/resources/g2/track/raptor/flat_to_steep_up_diag_2_2.png b/resources/g2/track/raptor/flat_to_steep_up_diag_2_2.png new file mode 100644 index 0000000000..251476d353 Binary files /dev/null and b/resources/g2/track/raptor/flat_to_steep_up_diag_2_2.png differ diff --git a/resources/g2/track/raptor/flat_to_steep_up_diag_2_3.png b/resources/g2/track/raptor/flat_to_steep_up_diag_2_3.png new file mode 100644 index 0000000000..3f240a661b Binary files /dev/null and b/resources/g2/track/raptor/flat_to_steep_up_diag_2_3.png differ diff --git a/resources/g2/track/raptor/flat_to_steep_up_diag_3_1.png b/resources/g2/track/raptor/flat_to_steep_up_diag_3_1.png new file mode 100644 index 0000000000..8a1cb8df81 Binary files /dev/null and b/resources/g2/track/raptor/flat_to_steep_up_diag_3_1.png differ diff --git a/resources/g2/track/raptor/flat_to_steep_up_diag_3_2.png b/resources/g2/track/raptor/flat_to_steep_up_diag_3_2.png new file mode 100644 index 0000000000..a53813c501 Binary files /dev/null and b/resources/g2/track/raptor/flat_to_steep_up_diag_3_2.png differ diff --git a/resources/g2/track/raptor/flat_to_steep_up_diag_3_3.png b/resources/g2/track/raptor/flat_to_steep_up_diag_3_3.png new file mode 100644 index 0000000000..76d7fcb7a2 Binary files /dev/null and b/resources/g2/track/raptor/flat_to_steep_up_diag_3_3.png differ diff --git a/resources/g2/track/raptor/flat_to_steep_up_diag_4_1.png b/resources/g2/track/raptor/flat_to_steep_up_diag_4_1.png new file mode 100644 index 0000000000..1ee8c16476 Binary files /dev/null and b/resources/g2/track/raptor/flat_to_steep_up_diag_4_1.png differ diff --git a/resources/g2/track/raptor/flat_to_steep_up_diag_4_2.png b/resources/g2/track/raptor/flat_to_steep_up_diag_4_2.png new file mode 100644 index 0000000000..89da8414eb Binary files /dev/null and b/resources/g2/track/raptor/flat_to_steep_up_diag_4_2.png differ diff --git a/resources/g2/track/raptor/flat_to_steep_up_diag_4_3.png b/resources/g2/track/raptor/flat_to_steep_up_diag_4_3.png new file mode 100644 index 0000000000..cafb747651 Binary files /dev/null and b/resources/g2/track/raptor/flat_to_steep_up_diag_4_3.png differ diff --git a/resources/g2/track/raptor/steep_to_flat_up_diag_1_1.png b/resources/g2/track/raptor/steep_to_flat_up_diag_1_1.png new file mode 100644 index 0000000000..4f3d08defc Binary files /dev/null and b/resources/g2/track/raptor/steep_to_flat_up_diag_1_1.png differ diff --git a/resources/g2/track/raptor/steep_to_flat_up_diag_1_2.png b/resources/g2/track/raptor/steep_to_flat_up_diag_1_2.png new file mode 100644 index 0000000000..5a26edb65a Binary files /dev/null and b/resources/g2/track/raptor/steep_to_flat_up_diag_1_2.png differ diff --git a/resources/g2/track/raptor/steep_to_flat_up_diag_1_3.png b/resources/g2/track/raptor/steep_to_flat_up_diag_1_3.png new file mode 100644 index 0000000000..b888b93b16 Binary files /dev/null and b/resources/g2/track/raptor/steep_to_flat_up_diag_1_3.png differ diff --git a/resources/g2/track/raptor/steep_to_flat_up_diag_2_1.png b/resources/g2/track/raptor/steep_to_flat_up_diag_2_1.png new file mode 100644 index 0000000000..251476d353 Binary files /dev/null and b/resources/g2/track/raptor/steep_to_flat_up_diag_2_1.png differ diff --git a/resources/g2/track/raptor/steep_to_flat_up_diag_2_2.png b/resources/g2/track/raptor/steep_to_flat_up_diag_2_2.png new file mode 100644 index 0000000000..251476d353 Binary files /dev/null and b/resources/g2/track/raptor/steep_to_flat_up_diag_2_2.png differ diff --git a/resources/g2/track/raptor/steep_to_flat_up_diag_2_3.png b/resources/g2/track/raptor/steep_to_flat_up_diag_2_3.png new file mode 100644 index 0000000000..66f30a8b96 Binary files /dev/null and b/resources/g2/track/raptor/steep_to_flat_up_diag_2_3.png differ diff --git a/resources/g2/track/raptor/steep_to_flat_up_diag_3_1.png b/resources/g2/track/raptor/steep_to_flat_up_diag_3_1.png new file mode 100644 index 0000000000..374d1edd6b Binary files /dev/null and b/resources/g2/track/raptor/steep_to_flat_up_diag_3_1.png differ diff --git a/resources/g2/track/raptor/steep_to_flat_up_diag_3_2.png b/resources/g2/track/raptor/steep_to_flat_up_diag_3_2.png new file mode 100644 index 0000000000..07931052a5 Binary files /dev/null and b/resources/g2/track/raptor/steep_to_flat_up_diag_3_2.png differ diff --git a/resources/g2/track/raptor/steep_to_flat_up_diag_3_3.png b/resources/g2/track/raptor/steep_to_flat_up_diag_3_3.png new file mode 100644 index 0000000000..5c67bcb43d Binary files /dev/null and b/resources/g2/track/raptor/steep_to_flat_up_diag_3_3.png differ diff --git a/resources/g2/track/raptor/steep_to_flat_up_diag_4_1.png b/resources/g2/track/raptor/steep_to_flat_up_diag_4_1.png new file mode 100644 index 0000000000..9885f187c3 Binary files /dev/null and b/resources/g2/track/raptor/steep_to_flat_up_diag_4_1.png differ diff --git a/resources/g2/track/raptor/steep_to_flat_up_diag_4_2.png b/resources/g2/track/raptor/steep_to_flat_up_diag_4_2.png new file mode 100644 index 0000000000..39de02f4ae Binary files /dev/null and b/resources/g2/track/raptor/steep_to_flat_up_diag_4_2.png differ diff --git a/resources/g2/track/raptor/steep_to_flat_up_diag_4_3.png b/resources/g2/track/raptor/steep_to_flat_up_diag_4_3.png new file mode 100644 index 0000000000..4d57c5bf00 Binary files /dev/null and b/resources/g2/track/raptor/steep_to_flat_up_diag_4_3.png differ diff --git a/src/openrct2-ui/UiStringIds.h b/src/openrct2-ui/UiStringIds.h index 8e2c15c7db..17b476d976 100644 --- a/src/openrct2-ui/UiStringIds.h +++ b/src/openrct2-ui/UiStringIds.h @@ -1103,8 +1103,8 @@ namespace OpenRCT2 STR_DRAWING_ENGINE_TIP = 5876, STR_EARLY_COMPLETION_TIP = 6227, STR_EDIT_ASSET_PACKS_BUTTON = 6640, - STR_EXPORT_EMSCRIPTEN = 6727, - STR_IMPORT_EMSCRIPTEN = 6728, + STR_EXPORT_EMSCRIPTEN = 6730, + STR_IMPORT_EMSCRIPTEN = 6731, STR_EDIT_THEMES_BUTTON = 5153, STR_EDIT_THEMES_BUTTON_TIP = 5837, STR_EFFECTS_GROUP = 6256, diff --git a/src/openrct2-ui/WindowManager.cpp b/src/openrct2-ui/WindowManager.cpp index 7db0f6aede..ae8f33e839 100644 --- a/src/openrct2-ui/WindowManager.cpp +++ b/src/openrct2-ui/WindowManager.cpp @@ -420,7 +420,7 @@ public: { auto rideIndex = intent.GetUIntExtra(INTENT_EXTRA_RIDE_ID); auto w = FindByClass(WindowClass::RideConstruction); - if (w == nullptr || w->number != rideIndex) + if (w == nullptr || w->number != static_cast(rideIndex)) { WindowCloseConstructionWindows(); _currentRideIndex = RideId::FromUnderlying(rideIndex); @@ -713,7 +713,7 @@ public: if (w->flags & WF_NO_BACKGROUND) { auto widgetIndex = FindWidgetFromPoint(*w.get(), screenCoords); - if (widgetIndex == -1) + if (widgetIndex == kWidgetIndexNull) continue; } @@ -736,14 +736,10 @@ public: w.OnPrepareDraw(); // Find the widget at point x, y - WidgetIndex widget_index = -1; - for (int32_t i = 0;; i++) + WidgetIndex widget_index = kWidgetIndexNull; + for (auto i = 0u; i < w.widgets.size(); i++) { const auto& widget = w.widgets[i]; - if (widget.type == WindowWidgetType::Last) - { - break; - } if (widget.type != WindowWidgetType::Empty && widget.IsVisible()) { @@ -756,7 +752,7 @@ public: } // Return next widget if a dropdown - if (widget_index != -1) + if (widget_index != kWidgetIndexNull) { const auto& widget = w.widgets[widget_index]; if (widget.type == WindowWidgetType::DropdownMenu) diff --git a/src/openrct2-ui/input/MouseInput.cpp b/src/openrct2-ui/input/MouseInput.cpp index c7c06bd2e1..f824c01d6a 100644 --- a/src/openrct2-ui/input/MouseInput.cpp +++ b/src/openrct2-ui/input/MouseInput.cpp @@ -41,1705 +41,1709 @@ #include #include -using namespace OpenRCT2; -using namespace OpenRCT2::Ui; -using namespace OpenRCT2::Ui::Windows; - -struct RCTMouseData +namespace OpenRCT2 { - uint32_t x; - uint32_t y; - MouseState state; -}; + using namespace OpenRCT2::Ui; + using namespace OpenRCT2::Ui::Windows; -static RCTMouseData _mouseInputQueue[64]; -static uint8_t _mouseInputQueueReadIndex = 0; -static uint8_t _mouseInputQueueWriteIndex = 0; + struct RCTMouseData + { + uint32_t x; + uint32_t y; + MouseState state; + }; -static std::optional _ticksSinceDragStart; -static WidgetRef _dragWidget; -static uint8_t _dragScrollIndex; -static int32_t _originalWindowWidth; -static int32_t _originalWindowHeight; + static RCTMouseData _mouseInputQueue[64]; + static uint8_t _mouseInputQueueReadIndex = 0; + static uint8_t _mouseInputQueueWriteIndex = 0; -static uint8_t _currentScrollIndex; -static uint8_t _currentScrollArea; + static std::optional _ticksSinceDragStart; + static WidgetRef _dragWidget; + static uint8_t _dragScrollIndex; + static int32_t _originalWindowWidth; + static int32_t _originalWindowHeight; -ScreenCoordsXY gInputDragLast; + static uint8_t _currentScrollIndex; + static uint8_t _currentScrollArea; -uint32_t gTooltipCloseTimeout; -WidgetRef gTooltipWidget; -ScreenCoordsXY gTooltipCursor; + ScreenCoordsXY gInputDragLast; -static std::optional _clickRepeatTicks; + uint32_t gTooltipCloseTimeout; + WidgetRef gTooltipWidget; + ScreenCoordsXY gTooltipCursor; -static MouseState GameGetNextInput(ScreenCoordsXY& screenCoords); -static void InputWidgetOver(const ScreenCoordsXY& screenCoords, WindowBase* w, WidgetIndex widgetIndex); -static void InputWidgetOverChangeCheck(WindowClass windowClass, rct_windownumber windowNumber, WidgetIndex widgetIndex); -static void InputWidgetOverFlatbuttonInvalidate(); -void ProcessMouseOver(const ScreenCoordsXY& screenCoords); -void ProcessMouseTool(const ScreenCoordsXY& screenCoords); -void InvalidateScroll(); -static RCTMouseData* GetMouseInput(); -void TileElementRightClick(int32_t type, TileElement* tileElement, const ScreenCoordsXY& screenCoords); -static void GameHandleInputMouse(const ScreenCoordsXY& screenCoords, MouseState state); -static void InputWidgetLeft(const ScreenCoordsXY& screenCoords, WindowBase* w, WidgetIndex widgetIndex); -void InputStateWidgetPressed( - const ScreenCoordsXY& screenCoords, MouseState state, WidgetIndex widgetIndex, WindowBase* w, Widget* widget); -void SetCursor(CursorID cursor_id); -static void InputWindowPositionContinue( - WindowBase& w, const ScreenCoordsXY& lastScreenCoords, const ScreenCoordsXY& newScreenCoords); -static void InputWindowPositionEnd(WindowBase& w, const ScreenCoordsXY& screenCoords); -static void InputWindowResizeBegin(WindowBase& w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords); -static void InputWindowResizeContinue(WindowBase& w, const ScreenCoordsXY& screenCoords); -static void InputWindowResizeEnd(); -static void InputViewportDragBegin(WindowBase& w); -static void InputViewportDragContinue(); -static void InputViewportDragEnd(); -static void InputScrollBegin(WindowBase& w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords); -static void InputScrollContinue(WindowBase& w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords); -static void InputScrollEnd(); -static void InputScrollPartUpdateHThumb(WindowBase& w, WidgetIndex widgetIndex, int32_t x, int32_t scroll_id); -static void InputScrollPartUpdateHLeft(WindowBase& w, WidgetIndex widgetIndex, int32_t scroll_id); -static void InputScrollPartUpdateHRight(WindowBase& w, WidgetIndex widgetIndex, int32_t scroll_id); -static void InputScrollPartUpdateVThumb(WindowBase& w, WidgetIndex widgetIndex, int32_t y, int32_t scroll_id); -static void InputScrollPartUpdateVTop(WindowBase& w, WidgetIndex widgetIndex, int32_t scroll_id); -static void InputScrollPartUpdateVBottom(WindowBase& w, WidgetIndex widgetIndex, int32_t scroll_id); -static void InputUpdateTooltip(WindowBase* w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords); + static std::optional _clickRepeatTicks; + + static MouseState GameGetNextInput(ScreenCoordsXY& screenCoords); + static void InputWidgetOver(const ScreenCoordsXY& screenCoords, WindowBase* w, WidgetIndex widgetIndex); + static void InputWidgetOverChangeCheck(WindowClass windowClass, rct_windownumber windowNumber, WidgetIndex widgetIndex); + static void InputWidgetOverFlatbuttonInvalidate(); + void ProcessMouseOver(const ScreenCoordsXY& screenCoords); + void ProcessMouseTool(const ScreenCoordsXY& screenCoords); + void InvalidateScroll(); + static RCTMouseData* GetMouseInput(); + void TileElementRightClick(int32_t type, TileElement* tileElement, const ScreenCoordsXY& screenCoords); + static void GameHandleInputMouse(const ScreenCoordsXY& screenCoords, MouseState state); + static void InputWidgetLeft(const ScreenCoordsXY& screenCoords, WindowBase* w, WidgetIndex widgetIndex); + void InputStateWidgetPressed( + const ScreenCoordsXY& screenCoords, MouseState state, WidgetIndex widgetIndex, WindowBase* w, Widget* widget); + void SetCursor(CursorID cursor_id); + static void InputWindowPositionContinue( + WindowBase& w, const ScreenCoordsXY& lastScreenCoords, const ScreenCoordsXY& newScreenCoords); + static void InputWindowPositionEnd(WindowBase& w, const ScreenCoordsXY& screenCoords); + static void InputWindowResizeBegin(WindowBase& w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords); + static void InputWindowResizeContinue(WindowBase& w, const ScreenCoordsXY& screenCoords); + static void InputWindowResizeEnd(); + static void InputViewportDragBegin(WindowBase& w); + static void InputViewportDragContinue(); + static void InputViewportDragEnd(); + static void InputScrollBegin(WindowBase& w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords); + static void InputScrollContinue(WindowBase& w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords); + static void InputScrollEnd(); + static void InputScrollPartUpdateHThumb(WindowBase& w, WidgetIndex widgetIndex, int32_t x, int32_t scroll_id); + static void InputScrollPartUpdateHLeft(WindowBase& w, WidgetIndex widgetIndex, int32_t scroll_id); + static void InputScrollPartUpdateHRight(WindowBase& w, WidgetIndex widgetIndex, int32_t scroll_id); + static void InputScrollPartUpdateVThumb(WindowBase& w, WidgetIndex widgetIndex, int32_t y, int32_t scroll_id); + static void InputScrollPartUpdateVTop(WindowBase& w, WidgetIndex widgetIndex, int32_t scroll_id); + static void InputScrollPartUpdateVBottom(WindowBase& w, WidgetIndex widgetIndex, int32_t scroll_id); + static void InputUpdateTooltip(WindowBase* w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords); #pragma region Mouse input -/** - * - * rct2: 0x006EA627 - */ -void GameHandleInput() -{ - InvalidateAllWindowsAfterInput(); - - MouseState state; - ScreenCoordsXY screenCoords; - while ((state = GameGetNextInput(screenCoords)) != MouseState::Released) + /** + * + * rct2: 0x006EA627 + */ + void GameHandleInput() { - GameHandleInputMouse(screenCoords, state); + InvalidateAllWindowsAfterInput(); + + MouseState state; + ScreenCoordsXY screenCoords; + while ((state = GameGetNextInput(screenCoords)) != MouseState::Released) + { + GameHandleInputMouse(screenCoords, state); + } + + if (_inputFlags & INPUT_FLAG_5) + { + GameHandleInputMouse(screenCoords, state); + } + else + { + int32_t screenWidth = ContextGetWidth(); + int32_t screenHeight = ContextGetHeight(); + screenCoords.x = std::clamp(screenCoords.x, 0, screenWidth - 1); + screenCoords.y = std::clamp(screenCoords.y, 0, screenHeight - 1); + + GameHandleInputMouse(screenCoords, state); + ProcessMouseOver(screenCoords); + ProcessMouseTool(screenCoords); + } } - if (_inputFlags & INPUT_FLAG_5) + /** + * + * rct2: 0x006E83C7 + */ + static MouseState GameGetNextInput(ScreenCoordsXY& screenCoords) { - GameHandleInputMouse(screenCoords, state); - } - else - { - int32_t screenWidth = ContextGetWidth(); - int32_t screenHeight = ContextGetHeight(); - screenCoords.x = std::clamp(screenCoords.x, 0, screenWidth - 1); - screenCoords.y = std::clamp(screenCoords.y, 0, screenHeight - 1); + RCTMouseData* input = GetMouseInput(); + if (input == nullptr) + { + const CursorState* cursorState = ContextGetCursorState(); + screenCoords = cursorState->position; + return MouseState::Released; + } - GameHandleInputMouse(screenCoords, state); - ProcessMouseOver(screenCoords); - ProcessMouseTool(screenCoords); - } -} - -/** - * - * rct2: 0x006E83C7 - */ -static MouseState GameGetNextInput(ScreenCoordsXY& screenCoords) -{ - RCTMouseData* input = GetMouseInput(); - if (input == nullptr) - { - const CursorState* cursorState = ContextGetCursorState(); - screenCoords = cursorState->position; - return MouseState::Released; + screenCoords.x = input->x; + screenCoords.y = input->y; + return input->state; } - screenCoords.x = input->x; - screenCoords.y = input->y; - return input->state; -} - -/** - * - * rct2: 0x00407074 - */ -static RCTMouseData* GetMouseInput() -{ - // Check if that location has been written to yet - if (_mouseInputQueueReadIndex == _mouseInputQueueWriteIndex) + /** + * + * rct2: 0x00407074 + */ + static RCTMouseData* GetMouseInput() { - return nullptr; + // Check if that location has been written to yet + if (_mouseInputQueueReadIndex == _mouseInputQueueWriteIndex) + { + return nullptr; + } + + RCTMouseData* result = &_mouseInputQueue[_mouseInputQueueReadIndex]; + _mouseInputQueueReadIndex = (_mouseInputQueueReadIndex + 1) % std::size(_mouseInputQueue); + return result; } - RCTMouseData* result = &_mouseInputQueue[_mouseInputQueueReadIndex]; - _mouseInputQueueReadIndex = (_mouseInputQueueReadIndex + 1) % std::size(_mouseInputQueue); - return result; -} - -/** - * - * rct2: 0x006E957F - */ -static void InputScrollDragBegin(const ScreenCoordsXY& screenCoords, WindowBase* w, WidgetIndex widgetIndex) -{ - _inputState = InputState::ScrollRight; - gInputDragLast = screenCoords; - _dragWidget.window_classification = w->classification; - _dragWidget.window_number = w->number; - _dragWidget.widget_index = widgetIndex; - _ticksSinceDragStart = gCurrentRealTimeTicks; - - _dragScrollIndex = WindowGetScrollDataIndex(*w, widgetIndex); - ContextHideCursor(); -} - -/** - * Based on (heavily changed) - * rct2: 0x006E9E0E, 0x006E9ED0 - */ -static void InputScrollDragContinue(const ScreenCoordsXY& screenCoords, WindowBase* w) -{ - WidgetIndex widgetIndex = _dragWidget.widget_index; - uint8_t scrollIndex = _dragScrollIndex; - - const auto& widget = w->widgets[widgetIndex]; - auto& scroll = w->scrolls[scrollIndex]; - - ScreenCoordsXY differentialCoords = screenCoords - gInputDragLast; - if (differentialCoords.x == 0 && differentialCoords.y == 0) - return; - - if (scroll.flags & HSCROLLBAR_VISIBLE) + /** + * + * rct2: 0x006E957F + */ + static void InputScrollDragBegin(const ScreenCoordsXY& screenCoords, WindowBase* w, WidgetIndex widgetIndex) { - int16_t size = widget.width() - 1; - if (scroll.flags & VSCROLLBAR_VISIBLE) - size -= 11; - size = std::max(0, scroll.contentWidth - size); - scroll.contentOffsetX = std::min(std::max(0, scroll.contentOffsetX + differentialCoords.x), size); + _inputState = InputState::ScrollRight; + gInputDragLast = screenCoords; + _dragWidget.window_classification = w->classification; + _dragWidget.window_number = w->number; + _dragWidget.widget_index = widgetIndex; + _ticksSinceDragStart = gCurrentRealTimeTicks; + + _dragScrollIndex = WindowGetScrollDataIndex(*w, widgetIndex); + ContextHideCursor(); } - if (scroll.flags & VSCROLLBAR_VISIBLE) + /** + * Based on (heavily changed) + * rct2: 0x006E9E0E, 0x006E9ED0 + */ + static void InputScrollDragContinue(const ScreenCoordsXY& screenCoords, WindowBase* w) { - int16_t size = widget.height() - 1; + WidgetIndex widgetIndex = _dragWidget.widget_index; + uint8_t scrollIndex = _dragScrollIndex; + + const auto& widget = w->widgets[widgetIndex]; + auto& scroll = w->scrolls[scrollIndex]; + + ScreenCoordsXY differentialCoords = screenCoords - gInputDragLast; + if (differentialCoords.x == 0 && differentialCoords.y == 0) + return; + if (scroll.flags & HSCROLLBAR_VISIBLE) - size -= 11; - size = std::max(0, scroll.contentHeight - size); - scroll.contentOffsetY = std::min(std::max(0, scroll.contentOffsetY + differentialCoords.y), size); + { + int16_t size = widget.width() - 1; + if (scroll.flags & VSCROLLBAR_VISIBLE) + size -= 11; + size = std::max(0, scroll.contentWidth - size); + scroll.contentOffsetX = std::min(std::max(0, scroll.contentOffsetX + differentialCoords.x), size); + } + + if (scroll.flags & VSCROLLBAR_VISIBLE) + { + int16_t size = widget.height() - 1; + if (scroll.flags & HSCROLLBAR_VISIBLE) + size -= 11; + size = std::max(0, scroll.contentHeight - size); + scroll.contentOffsetY = std::min(std::max(0, scroll.contentOffsetY + differentialCoords.y), size); + } + + WidgetScrollUpdateThumbs(*w, widgetIndex); + WindowInvalidateByNumber(w->classification, w->number); + + ScreenCoordsXY fixedCursorPosition = { + static_cast(std::ceil(gInputDragLast.x * Config::Get().general.WindowScale)), + static_cast(std::ceil(gInputDragLast.y * Config::Get().general.WindowScale)) + }; + + ContextSetCursorPosition(fixedCursorPosition); } - WidgetScrollUpdateThumbs(*w, widgetIndex); - WindowInvalidateByNumber(w->classification, w->number); - - ScreenCoordsXY fixedCursorPosition = { - static_cast(std::ceil(gInputDragLast.x * Config::Get().general.WindowScale)), - static_cast(std::ceil(gInputDragLast.y * Config::Get().general.WindowScale)) - }; - - ContextSetCursorPosition(fixedCursorPosition); -} - -/** - * - * rct2: 0x006E8ACB - */ -static void InputScrollRight(const ScreenCoordsXY& screenCoords, MouseState state) -{ - auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); - WindowBase* w = windowMgr->FindByNumber(_dragWidget.window_classification, _dragWidget.window_number); - if (w == nullptr) + /** + * + * rct2: 0x006E8ACB + */ + static void InputScrollRight(const ScreenCoordsXY& screenCoords, MouseState state) { - ContextShowCursor(); - _inputState = InputState::Reset; - return; - } - - switch (state) - { - case MouseState::Released: - if (screenCoords.x != 0 || screenCoords.y != 0) - { - _ticksSinceDragStart = std::nullopt; - InputScrollDragContinue(screenCoords, w); - } - break; - case MouseState::RightRelease: - _inputState = InputState::Reset; + auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); + WindowBase* w = windowMgr->FindByNumber(_dragWidget.window_classification, _dragWidget.window_number); + if (w == nullptr) + { ContextShowCursor(); - break; - case MouseState::LeftPress: - case MouseState::LeftRelease: - case MouseState::RightPress: - // Function only handles right button, so it's the only one relevant - break; - } -} + _inputState = InputState::Reset; + return; + } -/** - * - * rct2: 0x006E8655 - */ -static void GameHandleInputMouse(const ScreenCoordsXY& screenCoords, MouseState state) -{ - WindowBase* w; - Widget* widget; - WidgetIndex widgetIndex; - - auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); - - // Get window and widget under cursor position - w = windowMgr->FindFromPoint(screenCoords); - widgetIndex = w == nullptr ? -1 : windowMgr->FindWidgetFromPoint(*w, screenCoords); - widget = widgetIndex == -1 ? nullptr : &w->widgets[widgetIndex]; - - switch (_inputState) - { - case InputState::Reset: - WindowTooltipReset(screenCoords); - // fall-through - case InputState::Normal: - switch (state) - { - case MouseState::Released: - InputWidgetOver(screenCoords, w, widgetIndex); - break; - case MouseState::LeftPress: - InputWidgetLeft(screenCoords, w, widgetIndex); - break; - case MouseState::RightPress: - WindowCloseByClass(WindowClass::Tooltip); - - if (w != nullptr) - { - w = WindowBringToFront(*w); - } - - if (widgetIndex != -1) - { - switch (widget->type) - { - case WindowWidgetType::Viewport: - if (!(gScreenFlags & (SCREEN_FLAGS_TRACK_MANAGER | SCREEN_FLAGS_TITLE_DEMO))) - { - InputViewportDragBegin(*w); - } - break; - case WindowWidgetType::Scroll: - InputScrollDragBegin(screenCoords, w, widgetIndex); - break; - default: - break; - } - } - break; - case MouseState::LeftRelease: - case MouseState::RightRelease: - // In this switch only button presses are relevant - break; - } - break; - case InputState::WidgetPressed: - InputStateWidgetPressed(screenCoords, state, widgetIndex, w, widget); - break; - case InputState::PositioningWindow: - w = windowMgr->FindByNumber(_dragWidget.window_classification, _dragWidget.window_number); - if (w == nullptr) - { - _inputState = InputState::Reset; - } - else - { - InputWindowPositionContinue(*w, gInputDragLast, screenCoords); - if (state == MouseState::LeftRelease) + switch (state) + { + case MouseState::Released: + if (screenCoords.x != 0 || screenCoords.y != 0) { - InputWindowPositionEnd(*w, screenCoords); + _ticksSinceDragStart = std::nullopt; + InputScrollDragContinue(screenCoords, w); } - } - break; - case InputState::ViewportRight: - if (state == MouseState::Released) - { - InputViewportDragContinue(); - } - else if (state == MouseState::RightRelease) - { - InputViewportDragEnd(); - if (_ticksSinceDragStart.has_value() && gCurrentRealTimeTicks - _ticksSinceDragStart.value() < 500) - { - // If the user pressed the right mouse button for less than 500 ticks, interpret as right click - ViewportInteractionRightClick(screenCoords); - } - } - break; - case InputState::DropdownActive: - InputStateWidgetPressed(screenCoords, state, widgetIndex, w, widget); - break; - case InputState::ViewportLeft: - w = windowMgr->FindByNumber(_dragWidget.window_classification, _dragWidget.window_number); - if (w == nullptr) - { - _inputState = InputState::Reset; break; - } + case MouseState::RightRelease: + _inputState = InputState::Reset; + ContextShowCursor(); + break; + case MouseState::LeftPress: + case MouseState::LeftRelease: + case MouseState::RightPress: + // Function only handles right button, so it's the only one relevant + break; + } + } - switch (state) - { - case MouseState::Released: - if (w->viewport == nullptr) - { - _inputState = InputState::Reset; + /** + * + * rct2: 0x006E8655 + */ + static void GameHandleInputMouse(const ScreenCoordsXY& screenCoords, MouseState state) + { + WindowBase* w; + Widget* widget; + WidgetIndex widgetIndex; + + auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); + + // Get window and widget under cursor position + w = windowMgr->FindFromPoint(screenCoords); + widgetIndex = w == nullptr ? -1 : windowMgr->FindWidgetFromPoint(*w, screenCoords); + widget = widgetIndex == kWidgetIndexNull ? nullptr : &w->widgets[widgetIndex]; + + switch (_inputState) + { + case InputState::Reset: + WindowTooltipReset(screenCoords); + // fall-through + case InputState::Normal: + switch (state) + { + case MouseState::Released: + InputWidgetOver(screenCoords, w, widgetIndex); break; - } - - if (!InputTestFlag(INPUT_FLAG_4)) + case MouseState::LeftPress: + InputWidgetLeft(screenCoords, w, widgetIndex); break; + case MouseState::RightPress: + WindowCloseByClass(WindowClass::Tooltip); - if (w->classification != _dragWidget.window_classification || w->number != _dragWidget.window_number - || !(_inputFlags & INPUT_FLAG_TOOL_ACTIVE)) - { - break; - } - - w = windowMgr->FindByNumber(gCurrentToolWidget.window_classification, gCurrentToolWidget.window_number); - if (w == nullptr) - { - break; - } - - w->OnToolDrag(gCurrentToolWidget.widget_index, screenCoords); - break; - case MouseState::LeftRelease: - _inputState = InputState::Reset; - if (_dragWidget.window_number == w->number) - { - if ((_inputFlags & INPUT_FLAG_TOOL_ACTIVE)) + if (w != nullptr) { - w = windowMgr->FindByNumber( - gCurrentToolWidget.window_classification, gCurrentToolWidget.window_number); - if (w != nullptr) + w = WindowBringToFront(*w); + } + + if (widgetIndex != kWidgetIndexNull) + { + switch (widget->type) { - w->OnToolUp(gCurrentToolWidget.widget_index, screenCoords); + case WindowWidgetType::Viewport: + if (!(gScreenFlags & (SCREEN_FLAGS_TRACK_MANAGER | SCREEN_FLAGS_TITLE_DEMO))) + { + InputViewportDragBegin(*w); + } + break; + case WindowWidgetType::Scroll: + InputScrollDragBegin(screenCoords, w, widgetIndex); + break; + default: + break; } } - else if (!(_inputFlags & INPUT_FLAG_4)) - { - ViewportInteractionLeftClick(screenCoords); - } + break; + case MouseState::LeftRelease: + case MouseState::RightRelease: + // In this switch only button presses are relevant + break; + } + break; + case InputState::WidgetPressed: + InputStateWidgetPressed(screenCoords, state, widgetIndex, w, widget); + break; + case InputState::PositioningWindow: + w = windowMgr->FindByNumber(_dragWidget.window_classification, _dragWidget.window_number); + if (w == nullptr) + { + _inputState = InputState::Reset; + } + else + { + InputWindowPositionContinue(*w, gInputDragLast, screenCoords); + if (state == MouseState::LeftRelease) + { + InputWindowPositionEnd(*w, screenCoords); } - break; - case MouseState::LeftPress: - case MouseState::RightPress: - case MouseState::RightRelease: - // In this switch only left button release is relevant - break; - } - break; - case InputState::ScrollLeft: - switch (state) - { - case MouseState::Released: - InputScrollContinue(*w, widgetIndex, screenCoords); - break; - case MouseState::LeftRelease: - InputScrollEnd(); - break; - case MouseState::LeftPress: - case MouseState::RightPress: - case MouseState::RightRelease: - // In this switch only left button release is relevant - break; - } - break; - case InputState::Resizing: - w = windowMgr->FindByNumber(_dragWidget.window_classification, _dragWidget.window_number); - if (w == nullptr) - { - _inputState = InputState::Reset; - } - else - { - if (state == MouseState::LeftRelease) - { - InputWindowResizeEnd(); } - if (state == MouseState::Released || state == MouseState::LeftRelease) + break; + case InputState::ViewportRight: + if (state == MouseState::Released) { - InputWindowResizeContinue(*w, screenCoords); + InputViewportDragContinue(); } - } - break; - case InputState::ScrollRight: - InputScrollRight(screenCoords, state); - break; + else if (state == MouseState::RightRelease) + { + InputViewportDragEnd(); + if (_ticksSinceDragStart.has_value() && gCurrentRealTimeTicks - _ticksSinceDragStart.value() < 500) + { + // If the user pressed the right mouse button for less than 500 ticks, interpret as right click + ViewportInteractionRightClick(screenCoords); + } + } + break; + case InputState::DropdownActive: + InputStateWidgetPressed(screenCoords, state, widgetIndex, w, widget); + break; + case InputState::ViewportLeft: + w = windowMgr->FindByNumber(_dragWidget.window_classification, _dragWidget.window_number); + if (w == nullptr) + { + _inputState = InputState::Reset; + break; + } + + switch (state) + { + case MouseState::Released: + if (w->viewport == nullptr) + { + _inputState = InputState::Reset; + break; + } + + if (!InputTestFlag(INPUT_FLAG_4)) + break; + + if (w->classification != _dragWidget.window_classification || w->number != _dragWidget.window_number + || !(_inputFlags & INPUT_FLAG_TOOL_ACTIVE)) + { + break; + } + + w = windowMgr->FindByNumber(gCurrentToolWidget.window_classification, gCurrentToolWidget.window_number); + if (w == nullptr) + { + break; + } + + w->OnToolDrag(gCurrentToolWidget.widget_index, screenCoords); + break; + case MouseState::LeftRelease: + _inputState = InputState::Reset; + if (_dragWidget.window_number == w->number) + { + if ((_inputFlags & INPUT_FLAG_TOOL_ACTIVE)) + { + w = windowMgr->FindByNumber( + gCurrentToolWidget.window_classification, gCurrentToolWidget.window_number); + if (w != nullptr) + { + w->OnToolUp(gCurrentToolWidget.widget_index, screenCoords); + } + } + else if (!(_inputFlags & INPUT_FLAG_4)) + { + ViewportInteractionLeftClick(screenCoords); + } + } + break; + case MouseState::LeftPress: + case MouseState::RightPress: + case MouseState::RightRelease: + // In this switch only left button release is relevant + break; + } + break; + case InputState::ScrollLeft: + switch (state) + { + case MouseState::Released: + InputScrollContinue(*w, widgetIndex, screenCoords); + break; + case MouseState::LeftRelease: + InputScrollEnd(); + break; + case MouseState::LeftPress: + case MouseState::RightPress: + case MouseState::RightRelease: + // In this switch only left button release is relevant + break; + } + break; + case InputState::Resizing: + w = windowMgr->FindByNumber(_dragWidget.window_classification, _dragWidget.window_number); + if (w == nullptr) + { + _inputState = InputState::Reset; + } + else + { + if (state == MouseState::LeftRelease) + { + InputWindowResizeEnd(); + } + if (state == MouseState::Released || state == MouseState::LeftRelease) + { + InputWindowResizeContinue(*w, screenCoords); + } + } + break; + case InputState::ScrollRight: + InputScrollRight(screenCoords, state); + break; + } } -} #pragma region Window positioning / resizing -void InputWindowPositionBegin(WindowBase& w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords) -{ - _inputState = InputState::PositioningWindow; - gInputDragLast = screenCoords - w.windowPos; - _dragWidget.window_classification = w.classification; - _dragWidget.window_number = w.number; - _dragWidget.widget_index = widgetIndex; -} - -static void InputWindowPositionContinue( - WindowBase& w, const ScreenCoordsXY& lastScreenCoords, const ScreenCoordsXY& newScreenCoords) -{ - int32_t snapProximity; - - snapProximity = (w.flags & WF_NO_SNAPPING) ? 0 : Config::Get().general.WindowSnapProximity; - WindowMoveAndSnap(w, newScreenCoords - lastScreenCoords, snapProximity); -} - -static void InputWindowPositionEnd(WindowBase& w, const ScreenCoordsXY& screenCoords) -{ - _inputState = InputState::Normal; - gTooltipCloseTimeout = 0; - gTooltipWidget = _dragWidget; - w.OnMoved(screenCoords); -} - -static void InputWindowResizeBegin(WindowBase& w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords) -{ - _inputState = InputState::Resizing; - gInputDragLast = screenCoords; - _dragWidget.window_classification = w.classification; - _dragWidget.window_number = w.number; - _dragWidget.widget_index = widgetIndex; - _originalWindowWidth = w.width; - _originalWindowHeight = w.height; -} - -static void InputWindowResizeContinue(WindowBase& w, const ScreenCoordsXY& screenCoords) -{ - if (screenCoords.y < static_cast(ContextGetHeight()) - 2) + void InputWindowPositionBegin(WindowBase& w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords) { - auto differentialCoords = screenCoords - gInputDragLast; - int32_t targetWidth = _originalWindowWidth + differentialCoords.x - w.width; - int32_t targetHeight = _originalWindowHeight + differentialCoords.y - w.height; - - WindowResize(w, targetWidth, targetHeight); + _inputState = InputState::PositioningWindow; + gInputDragLast = screenCoords - w.windowPos; + _dragWidget.window_classification = w.classification; + _dragWidget.window_number = w.number; + _dragWidget.widget_index = widgetIndex; } -} -static void InputWindowResizeEnd() -{ - _inputState = InputState::Normal; - gTooltipCloseTimeout = 0; - gTooltipWidget = _dragWidget; -} + static void InputWindowPositionContinue( + WindowBase& w, const ScreenCoordsXY& lastScreenCoords, const ScreenCoordsXY& newScreenCoords) + { + int32_t snapProximity; + + snapProximity = (w.flags & WF_NO_SNAPPING) ? 0 : Config::Get().general.WindowSnapProximity; + WindowMoveAndSnap(w, newScreenCoords - lastScreenCoords, snapProximity); + } + + static void InputWindowPositionEnd(WindowBase& w, const ScreenCoordsXY& screenCoords) + { + _inputState = InputState::Normal; + gTooltipCloseTimeout = 0; + gTooltipWidget = _dragWidget; + w.OnMoved(screenCoords); + } + + static void InputWindowResizeBegin(WindowBase& w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords) + { + _inputState = InputState::Resizing; + gInputDragLast = screenCoords; + _dragWidget.window_classification = w.classification; + _dragWidget.window_number = w.number; + _dragWidget.widget_index = widgetIndex; + _originalWindowWidth = w.width; + _originalWindowHeight = w.height; + } + + static void InputWindowResizeContinue(WindowBase& w, const ScreenCoordsXY& screenCoords) + { + if (screenCoords.y < static_cast(ContextGetHeight()) - 2) + { + auto differentialCoords = screenCoords - gInputDragLast; + int32_t targetWidth = _originalWindowWidth + differentialCoords.x - w.width; + int32_t targetHeight = _originalWindowHeight + differentialCoords.y - w.height; + + WindowResize(w, targetWidth, targetHeight); + } + } + + static void InputWindowResizeEnd() + { + _inputState = InputState::Normal; + gTooltipCloseTimeout = 0; + gTooltipWidget = _dragWidget; + } #pragma endregion #pragma region Viewport dragging -static void InputViewportDragBegin(WindowBase& w) -{ - w.flags &= ~WF_SCROLLING_TO_LOCATION; - _inputState = InputState::ViewportRight; - _dragWidget.window_classification = w.classification; - _dragWidget.window_number = w.number; - _ticksSinceDragStart = gCurrentRealTimeTicks; - auto cursorPosition = ContextGetCursorPosition(); - gInputDragLast = cursorPosition; - if (!Config::Get().general.InvertViewportDrag) + static void InputViewportDragBegin(WindowBase& w) { - ContextHideCursor(); - } - - WindowUnfollowSprite(w); - // gInputFlags |= INPUT_FLAG_5; -} - -static void InputViewportDragContinue() -{ - WindowBase* w; - Viewport* viewport; - - auto newDragCoords = ContextGetCursorPosition(); - - auto differentialCoords = newDragCoords - gInputDragLast; - if (differentialCoords.x == 0 && differentialCoords.y == 0) - return; - - auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); - w = windowMgr->FindByNumber(_dragWidget.window_classification, _dragWidget.window_number); - - // #3294: Window can be closed during a drag session, so just finish - // the session if the window no longer exists - if (w == nullptr) - { - InputViewportDragEnd(); - return; - } - - viewport = w->viewport; - if (viewport == nullptr) - { - ContextShowCursor(); - _inputState = InputState::Reset; - } - else if (differentialCoords.x != 0 || differentialCoords.y != 0) - { - if (!(w->flags & WF_NO_SCROLLING)) + w.flags &= ~WF_SCROLLING_TO_LOCATION; + _inputState = InputState::ViewportRight; + _dragWidget.window_classification = w.classification; + _dragWidget.window_number = w.number; + _ticksSinceDragStart = gCurrentRealTimeTicks; + auto cursorPosition = ContextGetCursorPosition(); + gInputDragLast = cursorPosition; + if (!Config::Get().general.InvertViewportDrag) { - // User dragged a scrollable viewport + ContextHideCursor(); + } - // If the drag time is less than 500 the "drag" is usually interpreted as a right click. - // As the user moved the mouse, don't interpret it as right click in any case. - _ticksSinceDragStart = std::nullopt; + WindowUnfollowSprite(w); + // gInputFlags |= INPUT_FLAG_5; + } - // applying the zoom only with negative values avoids a "deadzone" effect where small positive value round to zero. - const bool posX = differentialCoords.x > 0; - const bool posY = differentialCoords.y > 0; - differentialCoords.x = (viewport->zoom + 1).ApplyTo(-std::abs(differentialCoords.x)); - differentialCoords.y = (viewport->zoom + 1).ApplyTo(-std::abs(differentialCoords.y)); - differentialCoords.x = posX ? -differentialCoords.x : differentialCoords.x; - differentialCoords.y = posY ? -differentialCoords.y : differentialCoords.y; + static void InputViewportDragContinue() + { + WindowBase* w; + Viewport* viewport; - if (Config::Get().general.InvertViewportDrag) + auto newDragCoords = ContextGetCursorPosition(); + + auto differentialCoords = newDragCoords - gInputDragLast; + if (differentialCoords.x == 0 && differentialCoords.y == 0) + return; + + auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); + w = windowMgr->FindByNumber(_dragWidget.window_classification, _dragWidget.window_number); + + // #3294: Window can be closed during a drag session, so just finish + // the session if the window no longer exists + if (w == nullptr) + { + InputViewportDragEnd(); + return; + } + + viewport = w->viewport; + if (viewport == nullptr) + { + ContextShowCursor(); + _inputState = InputState::Reset; + } + else if (differentialCoords.x != 0 || differentialCoords.y != 0) + { + if (!(w->flags & WF_NO_SCROLLING)) { - w->savedViewPos -= differentialCoords; - } - else - { - w->savedViewPos += differentialCoords; + // User dragged a scrollable viewport + + // If the drag time is less than 500 the "drag" is usually interpreted as a right click. + // As the user moved the mouse, don't interpret it as right click in any case. + _ticksSinceDragStart = std::nullopt; + + // applying the zoom only with negative values avoids a "deadzone" effect where small positive value round to + // zero. + const bool posX = differentialCoords.x > 0; + const bool posY = differentialCoords.y > 0; + differentialCoords.x = (viewport->zoom + 1).ApplyTo(-std::abs(differentialCoords.x)); + differentialCoords.y = (viewport->zoom + 1).ApplyTo(-std::abs(differentialCoords.y)); + differentialCoords.x = posX ? -differentialCoords.x : differentialCoords.x; + differentialCoords.y = posY ? -differentialCoords.y : differentialCoords.y; + + if (Config::Get().general.InvertViewportDrag) + { + w->savedViewPos -= differentialCoords; + } + else + { + w->savedViewPos += differentialCoords; + } } } - } #ifndef __EMSCRIPTEN__ - const CursorState* cursorState = ContextGetCursorState(); - if (cursorState->touch || Config::Get().general.InvertViewportDrag) - { - gInputDragLast = newDragCoords; - } - else - { - ContextSetCursorPosition(gInputDragLast); - } + const CursorState* cursorState = ContextGetCursorState(); + if (cursorState->touch || Config::Get().general.InvertViewportDrag) + { + gInputDragLast = newDragCoords; + } + else + { + ContextSetCursorPosition(gInputDragLast); + } #else - gInputDragLast = newDragCoords; + gInputDragLast = newDragCoords; #endif -} + } -static void InputViewportDragEnd() -{ - _inputState = InputState::Reset; - ContextShowCursor(); -} + static void InputViewportDragEnd() + { + _inputState = InputState::Reset; + ContextShowCursor(); + } #pragma endregion #pragma region Scroll bars -static void InputScrollBegin(WindowBase& w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords) -{ - const auto& widget = w.widgets[widgetIndex]; - - _inputState = InputState::ScrollLeft; - gPressedWidget.window_classification = w.classification; - gPressedWidget.window_number = w.number; - gPressedWidget.widget_index = widgetIndex; - gTooltipCursor = screenCoords; - - int32_t scroll_area, scroll_id; - ScreenCoordsXY scrollCoords; - scroll_id = 0; // safety - WidgetScrollGetPart(w, &widget, screenCoords, scrollCoords, &scroll_area, &scroll_id); - - _currentScrollArea = scroll_area; - _currentScrollIndex = scroll_id; - w.OnScrollSelect(scroll_id, scroll_area); - if (scroll_area == SCROLL_PART_VIEW) + static void InputScrollBegin(WindowBase& w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords) { - w.OnScrollMouseDown(scroll_id, scrollCoords); - return; - } + const auto& widget = w.widgets[widgetIndex]; - const auto& widg = w.widgets[widgetIndex]; - auto& scroll = w.scrolls[scroll_id]; + _inputState = InputState::ScrollLeft; + gPressedWidget.window_classification = w.classification; + gPressedWidget.window_number = w.number; + gPressedWidget.widget_index = widgetIndex; + gTooltipCursor = screenCoords; - int32_t widget_width = widg.width() - 1; - if (scroll.flags & VSCROLLBAR_VISIBLE) - widget_width -= kScrollBarWidth + 1; - int32_t widget_content_width = std::max(scroll.contentWidth - widget_width, 0); + int32_t scroll_area, scroll_id; + ScreenCoordsXY scrollCoords; + scroll_id = 0; // safety + WidgetScrollGetPart(w, &widget, screenCoords, scrollCoords, &scroll_area, &scroll_id); - int32_t widget_height = widg.bottom - widg.top - 1; - if (scroll.flags & HSCROLLBAR_VISIBLE) - widget_height -= kScrollBarWidth + 1; - int32_t widget_content_height = std::max(scroll.contentHeight - widget_height, 0); + _currentScrollArea = scroll_area; + _currentScrollIndex = scroll_id; + w.OnScrollSelect(scroll_id, scroll_area); + if (scroll_area == SCROLL_PART_VIEW) + { + w.OnScrollMouseDown(scroll_id, scrollCoords); + return; + } - switch (scroll_area) - { - case SCROLL_PART_HSCROLLBAR_LEFT: - scroll.contentOffsetX = std::max(scroll.contentOffsetX - 3, 0); - break; - case SCROLL_PART_HSCROLLBAR_RIGHT: - scroll.contentOffsetX = std::min(scroll.contentOffsetX + 3, widget_content_width); - break; - case SCROLL_PART_HSCROLLBAR_LEFT_TROUGH: - scroll.contentOffsetX = std::max(scroll.contentOffsetX - widget_width, 0); - break; - case SCROLL_PART_HSCROLLBAR_RIGHT_TROUGH: - scroll.contentOffsetX = std::min(scroll.contentOffsetX + widget_width, widget_content_width); - break; - case SCROLL_PART_VSCROLLBAR_TOP: - scroll.contentOffsetY = std::max(scroll.contentOffsetY - 3, 0); - break; - case SCROLL_PART_VSCROLLBAR_BOTTOM: - scroll.contentOffsetY = std::min(scroll.contentOffsetY + 3, widget_content_height); - break; - case SCROLL_PART_VSCROLLBAR_TOP_TROUGH: - scroll.contentOffsetY = std::max(scroll.contentOffsetY - widget_height, 0); - break; - case SCROLL_PART_VSCROLLBAR_BOTTOM_TROUGH: - scroll.contentOffsetY = std::min(scroll.contentOffsetY + widget_height, widget_content_height); - break; - default: - break; - } - WidgetScrollUpdateThumbs(w, widgetIndex); - WindowInvalidateByNumber(w.classification, w.number); -} - -static void InputScrollContinue(WindowBase& w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords) -{ - int32_t scroll_part, scroll_id; - - const auto& widget = w.widgets[widgetIndex]; - if (w.classification != gPressedWidget.window_classification || w.number != gPressedWidget.window_number - || widgetIndex != gPressedWidget.widget_index) - { - InvalidateScroll(); - return; - } - - ScreenCoordsXY newScreenCoords; - WidgetScrollGetPart(w, &widget, screenCoords, newScreenCoords, &scroll_part, &scroll_id); - - if (_currentScrollArea == SCROLL_PART_HSCROLLBAR_THUMB) - { - int32_t originalTooltipCursorX = gTooltipCursor.x; - gTooltipCursor.x = screenCoords.x; - InputScrollPartUpdateHThumb(w, widgetIndex, screenCoords.x - originalTooltipCursorX, scroll_id); - return; - } - - if (_currentScrollArea == SCROLL_PART_VSCROLLBAR_THUMB) - { - int32_t originalTooltipCursorY = gTooltipCursor.y; - gTooltipCursor.y = screenCoords.y; - InputScrollPartUpdateVThumb(w, widgetIndex, screenCoords.y - originalTooltipCursorY, scroll_id); - return; - } - - if (scroll_part != _currentScrollArea) - { - InvalidateScroll(); - return; - } - - switch (scroll_part) - { - case SCROLL_PART_VIEW: - w.OnScrollMouseDrag(scroll_id, newScreenCoords); - break; - case SCROLL_PART_HSCROLLBAR_LEFT: - InputScrollPartUpdateHLeft(w, widgetIndex, scroll_id); - break; - case SCROLL_PART_HSCROLLBAR_RIGHT: - InputScrollPartUpdateHRight(w, widgetIndex, scroll_id); - break; - case SCROLL_PART_VSCROLLBAR_TOP: - InputScrollPartUpdateVTop(w, widgetIndex, scroll_id); - break; - case SCROLL_PART_VSCROLLBAR_BOTTOM: - InputScrollPartUpdateVBottom(w, widgetIndex, scroll_id); - break; - } -} - -static void InputScrollEnd() -{ - _inputState = InputState::Reset; - InvalidateScroll(); -} - -/** - * - * rct2: 0x006E98F2 - */ -static void InputScrollPartUpdateHThumb(WindowBase& w, WidgetIndex widgetIndex, int32_t x, int32_t scroll_id) -{ - const auto& widget = w.widgets[widgetIndex]; - auto& scroll = w.scrolls[scroll_id]; - - auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); - if (windowMgr->FindByNumber(w.classification, w.number) != nullptr) - { - int32_t newLeft; - newLeft = scroll.contentWidth; - newLeft *= x; - x = widget.width() - 21; - if (scroll.flags & VSCROLLBAR_VISIBLE) - x -= kScrollBarWidth + 1; - newLeft /= x; - x = newLeft; - scroll.flags |= HSCROLLBAR_THUMB_PRESSED; - newLeft = scroll.contentOffsetX; - newLeft += x; - if (newLeft < 0) - newLeft = 0; - x = widget.width() - 1; - if (scroll.flags & VSCROLLBAR_VISIBLE) - x -= kScrollBarWidth + 1; - x *= -1; - x += scroll.contentWidth; - if (x < 0) - x = 0; - if (newLeft > x) - newLeft = x; - scroll.contentOffsetX = newLeft; - WidgetScrollUpdateThumbs(w, widgetIndex); - WidgetInvalidateByNumber(w.classification, w.number, widgetIndex); - } -} - -/** - * - * rct2: 0x006E99A9 - */ -static void InputScrollPartUpdateVThumb(WindowBase& w, WidgetIndex widgetIndex, int32_t y, int32_t scroll_id) -{ - const auto& widget = w.widgets[widgetIndex]; - auto& scroll = w.scrolls[scroll_id]; - - auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); - if (windowMgr->FindByNumber(w.classification, w.number) != nullptr) - { - int32_t newTop; - newTop = scroll.contentHeight; - newTop *= y; - y = widget.height() - 21; - if (scroll.flags & HSCROLLBAR_VISIBLE) - y -= kScrollBarWidth + 1; - newTop /= y; - y = newTop; - scroll.flags |= VSCROLLBAR_THUMB_PRESSED; - newTop = scroll.contentOffsetY; - newTop += y; - if (newTop < 0) - newTop = 0; - y = widget.height() - 1; - if (scroll.flags & HSCROLLBAR_VISIBLE) - y -= kScrollBarWidth + 1; - y *= -1; - y += scroll.contentHeight; - if (y < 0) - y = 0; - if (newTop > y) - newTop = y; - scroll.contentOffsetY = newTop; - WidgetScrollUpdateThumbs(w, widgetIndex); - WidgetInvalidateByNumber(w.classification, w.number, widgetIndex); - } -} - -/** - * - * rct2: 0x006E9A60 - */ -static void InputScrollPartUpdateHLeft(WindowBase& w, WidgetIndex widgetIndex, int32_t scroll_id) -{ - auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); - if (windowMgr->FindByNumber(w.classification, w.number) != nullptr) - { + const auto& widg = w.widgets[widgetIndex]; auto& scroll = w.scrolls[scroll_id]; - scroll.flags |= HSCROLLBAR_LEFT_PRESSED; - if (scroll.contentOffsetX >= 3) - scroll.contentOffsetX -= 3; - WidgetScrollUpdateThumbs(w, widgetIndex); - WidgetInvalidateByNumber(w.classification, w.number, widgetIndex); - } -} -/** - * - * rct2: 0x006E9ABF - */ -static void InputScrollPartUpdateHRight(WindowBase& w, WidgetIndex widgetIndex, int32_t scroll_id) -{ - const auto& widget = w.widgets[widgetIndex]; - - auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); - if (windowMgr->FindByNumber(w.classification, w.number) != nullptr) - { - auto& scroll = w.scrolls[scroll_id]; - scroll.flags |= HSCROLLBAR_RIGHT_PRESSED; - scroll.contentOffsetX += 3; - int32_t newLeft = widget.width() - 1; + int32_t widget_width = widg.width() - 1; if (scroll.flags & VSCROLLBAR_VISIBLE) - newLeft -= kScrollBarWidth + 1; - newLeft *= -1; - newLeft += scroll.contentWidth; - if (newLeft < 0) - newLeft = 0; - if (scroll.contentOffsetX > newLeft) + widget_width -= kScrollBarWidth + 1; + int32_t widget_content_width = std::max(scroll.contentWidth - widget_width, 0); + + int32_t widget_height = widg.bottom - widg.top - 1; + if (scroll.flags & HSCROLLBAR_VISIBLE) + widget_height -= kScrollBarWidth + 1; + int32_t widget_content_height = std::max(scroll.contentHeight - widget_height, 0); + + switch (scroll_area) + { + case SCROLL_PART_HSCROLLBAR_LEFT: + scroll.contentOffsetX = std::max(scroll.contentOffsetX - 3, 0); + break; + case SCROLL_PART_HSCROLLBAR_RIGHT: + scroll.contentOffsetX = std::min(scroll.contentOffsetX + 3, widget_content_width); + break; + case SCROLL_PART_HSCROLLBAR_LEFT_TROUGH: + scroll.contentOffsetX = std::max(scroll.contentOffsetX - widget_width, 0); + break; + case SCROLL_PART_HSCROLLBAR_RIGHT_TROUGH: + scroll.contentOffsetX = std::min(scroll.contentOffsetX + widget_width, widget_content_width); + break; + case SCROLL_PART_VSCROLLBAR_TOP: + scroll.contentOffsetY = std::max(scroll.contentOffsetY - 3, 0); + break; + case SCROLL_PART_VSCROLLBAR_BOTTOM: + scroll.contentOffsetY = std::min(scroll.contentOffsetY + 3, widget_content_height); + break; + case SCROLL_PART_VSCROLLBAR_TOP_TROUGH: + scroll.contentOffsetY = std::max(scroll.contentOffsetY - widget_height, 0); + break; + case SCROLL_PART_VSCROLLBAR_BOTTOM_TROUGH: + scroll.contentOffsetY = std::min(scroll.contentOffsetY + widget_height, widget_content_height); + break; + default: + break; + } + WidgetScrollUpdateThumbs(w, widgetIndex); + WindowInvalidateByNumber(w.classification, w.number); + } + + static void InputScrollContinue(WindowBase& w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords) + { + int32_t scroll_part, scroll_id; + + const auto& widget = w.widgets[widgetIndex]; + if (w.classification != gPressedWidget.window_classification || w.number != gPressedWidget.window_number + || widgetIndex != gPressedWidget.widget_index) + { + InvalidateScroll(); + return; + } + + ScreenCoordsXY newScreenCoords; + WidgetScrollGetPart(w, &widget, screenCoords, newScreenCoords, &scroll_part, &scroll_id); + + if (_currentScrollArea == SCROLL_PART_HSCROLLBAR_THUMB) + { + int32_t originalTooltipCursorX = gTooltipCursor.x; + gTooltipCursor.x = screenCoords.x; + InputScrollPartUpdateHThumb(w, widgetIndex, screenCoords.x - originalTooltipCursorX, scroll_id); + return; + } + + if (_currentScrollArea == SCROLL_PART_VSCROLLBAR_THUMB) + { + int32_t originalTooltipCursorY = gTooltipCursor.y; + gTooltipCursor.y = screenCoords.y; + InputScrollPartUpdateVThumb(w, widgetIndex, screenCoords.y - originalTooltipCursorY, scroll_id); + return; + } + + if (scroll_part != _currentScrollArea) + { + InvalidateScroll(); + return; + } + + switch (scroll_part) + { + case SCROLL_PART_VIEW: + w.OnScrollMouseDrag(scroll_id, newScreenCoords); + break; + case SCROLL_PART_HSCROLLBAR_LEFT: + InputScrollPartUpdateHLeft(w, widgetIndex, scroll_id); + break; + case SCROLL_PART_HSCROLLBAR_RIGHT: + InputScrollPartUpdateHRight(w, widgetIndex, scroll_id); + break; + case SCROLL_PART_VSCROLLBAR_TOP: + InputScrollPartUpdateVTop(w, widgetIndex, scroll_id); + break; + case SCROLL_PART_VSCROLLBAR_BOTTOM: + InputScrollPartUpdateVBottom(w, widgetIndex, scroll_id); + break; + } + } + + static void InputScrollEnd() + { + _inputState = InputState::Reset; + InvalidateScroll(); + } + + /** + * + * rct2: 0x006E98F2 + */ + static void InputScrollPartUpdateHThumb(WindowBase& w, WidgetIndex widgetIndex, int32_t x, int32_t scroll_id) + { + const auto& widget = w.widgets[widgetIndex]; + auto& scroll = w.scrolls[scroll_id]; + + auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); + if (windowMgr->FindByNumber(w.classification, w.number) != nullptr) + { + int32_t newLeft; + newLeft = scroll.contentWidth; + newLeft *= x; + x = widget.width() - 21; + if (scroll.flags & VSCROLLBAR_VISIBLE) + x -= kScrollBarWidth + 1; + newLeft /= x; + x = newLeft; + scroll.flags |= HSCROLLBAR_THUMB_PRESSED; + newLeft = scroll.contentOffsetX; + newLeft += x; + if (newLeft < 0) + newLeft = 0; + x = widget.width() - 1; + if (scroll.flags & VSCROLLBAR_VISIBLE) + x -= kScrollBarWidth + 1; + x *= -1; + x += scroll.contentWidth; + if (x < 0) + x = 0; + if (newLeft > x) + newLeft = x; scroll.contentOffsetX = newLeft; - WidgetScrollUpdateThumbs(w, widgetIndex); - WidgetInvalidateByNumber(w.classification, w.number, widgetIndex); + WidgetScrollUpdateThumbs(w, widgetIndex); + WidgetInvalidateByNumber(w.classification, w.number, widgetIndex); + } } -} -/** - * - * rct2: 0x006E9C37 - */ -static void InputScrollPartUpdateVTop(WindowBase& w, WidgetIndex widgetIndex, int32_t scroll_id) -{ - auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); - if (windowMgr->FindByNumber(w.classification, w.number) != nullptr) + /** + * + * rct2: 0x006E99A9 + */ + static void InputScrollPartUpdateVThumb(WindowBase& w, WidgetIndex widgetIndex, int32_t y, int32_t scroll_id) { + const auto& widget = w.widgets[widgetIndex]; auto& scroll = w.scrolls[scroll_id]; - scroll.flags |= VSCROLLBAR_UP_PRESSED; - if (scroll.contentOffsetY >= 3) - scroll.contentOffsetY -= 3; - WidgetScrollUpdateThumbs(w, widgetIndex); - WidgetInvalidateByNumber(w.classification, w.number, widgetIndex); - } -} -/** - * - * rct2: 0x006E9C96 - */ -static void InputScrollPartUpdateVBottom(WindowBase& w, WidgetIndex widgetIndex, int32_t scroll_id) -{ - const auto& widget = w.widgets[widgetIndex]; - - auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); - if (windowMgr->FindByNumber(w.classification, w.number) != nullptr) - { - auto& scroll = w.scrolls[scroll_id]; - scroll.flags |= VSCROLLBAR_DOWN_PRESSED; - scroll.contentOffsetY += 3; - int32_t newTop = widget.height() - 1; - if (scroll.flags & HSCROLLBAR_VISIBLE) - newTop -= kScrollBarWidth + 1; - newTop *= -1; - newTop += scroll.contentHeight; - if (newTop < 0) - newTop = 0; - if (scroll.contentOffsetY > newTop) + auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); + if (windowMgr->FindByNumber(w.classification, w.number) != nullptr) + { + int32_t newTop; + newTop = scroll.contentHeight; + newTop *= y; + y = widget.height() - 21; + if (scroll.flags & HSCROLLBAR_VISIBLE) + y -= kScrollBarWidth + 1; + newTop /= y; + y = newTop; + scroll.flags |= VSCROLLBAR_THUMB_PRESSED; + newTop = scroll.contentOffsetY; + newTop += y; + if (newTop < 0) + newTop = 0; + y = widget.height() - 1; + if (scroll.flags & HSCROLLBAR_VISIBLE) + y -= kScrollBarWidth + 1; + y *= -1; + y += scroll.contentHeight; + if (y < 0) + y = 0; + if (newTop > y) + newTop = y; scroll.contentOffsetY = newTop; - WidgetScrollUpdateThumbs(w, widgetIndex); - WidgetInvalidateByNumber(w.classification, w.number, widgetIndex); + WidgetScrollUpdateThumbs(w, widgetIndex); + WidgetInvalidateByNumber(w.classification, w.number, widgetIndex); + } + } + + /** + * + * rct2: 0x006E9A60 + */ + static void InputScrollPartUpdateHLeft(WindowBase& w, WidgetIndex widgetIndex, int32_t scroll_id) + { + auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); + if (windowMgr->FindByNumber(w.classification, w.number) != nullptr) + { + auto& scroll = w.scrolls[scroll_id]; + scroll.flags |= HSCROLLBAR_LEFT_PRESSED; + if (scroll.contentOffsetX >= 3) + scroll.contentOffsetX -= 3; + WidgetScrollUpdateThumbs(w, widgetIndex); + WidgetInvalidateByNumber(w.classification, w.number, widgetIndex); + } + } + + /** + * + * rct2: 0x006E9ABF + */ + static void InputScrollPartUpdateHRight(WindowBase& w, WidgetIndex widgetIndex, int32_t scroll_id) + { + const auto& widget = w.widgets[widgetIndex]; + + auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); + if (windowMgr->FindByNumber(w.classification, w.number) != nullptr) + { + auto& scroll = w.scrolls[scroll_id]; + scroll.flags |= HSCROLLBAR_RIGHT_PRESSED; + scroll.contentOffsetX += 3; + int32_t newLeft = widget.width() - 1; + if (scroll.flags & VSCROLLBAR_VISIBLE) + newLeft -= kScrollBarWidth + 1; + newLeft *= -1; + newLeft += scroll.contentWidth; + if (newLeft < 0) + newLeft = 0; + if (scroll.contentOffsetX > newLeft) + scroll.contentOffsetX = newLeft; + WidgetScrollUpdateThumbs(w, widgetIndex); + WidgetInvalidateByNumber(w.classification, w.number, widgetIndex); + } + } + + /** + * + * rct2: 0x006E9C37 + */ + static void InputScrollPartUpdateVTop(WindowBase& w, WidgetIndex widgetIndex, int32_t scroll_id) + { + auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); + if (windowMgr->FindByNumber(w.classification, w.number) != nullptr) + { + auto& scroll = w.scrolls[scroll_id]; + scroll.flags |= VSCROLLBAR_UP_PRESSED; + if (scroll.contentOffsetY >= 3) + scroll.contentOffsetY -= 3; + WidgetScrollUpdateThumbs(w, widgetIndex); + WidgetInvalidateByNumber(w.classification, w.number, widgetIndex); + } + } + + /** + * + * rct2: 0x006E9C96 + */ + static void InputScrollPartUpdateVBottom(WindowBase& w, WidgetIndex widgetIndex, int32_t scroll_id) + { + const auto& widget = w.widgets[widgetIndex]; + + auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); + if (windowMgr->FindByNumber(w.classification, w.number) != nullptr) + { + auto& scroll = w.scrolls[scroll_id]; + scroll.flags |= VSCROLLBAR_DOWN_PRESSED; + scroll.contentOffsetY += 3; + int32_t newTop = widget.height() - 1; + if (scroll.flags & HSCROLLBAR_VISIBLE) + newTop -= kScrollBarWidth + 1; + newTop *= -1; + newTop += scroll.contentHeight; + if (newTop < 0) + newTop = 0; + if (scroll.contentOffsetY > newTop) + scroll.contentOffsetY = newTop; + WidgetScrollUpdateThumbs(w, widgetIndex); + WidgetInvalidateByNumber(w.classification, w.number, widgetIndex); + } } -} #pragma endregion #pragma region Widgets -/** - * - * rct2: 0x006E9253 - */ -static void InputWidgetOver(const ScreenCoordsXY& screenCoords, WindowBase* w, WidgetIndex widgetIndex) -{ - WindowClass windowClass = WindowClass::Null; - rct_windownumber windowNumber = 0; - Widget* widget = nullptr; - - if (w != nullptr) + /** + * + * rct2: 0x006E9253 + */ + static void InputWidgetOver(const ScreenCoordsXY& screenCoords, WindowBase* w, WidgetIndex widgetIndex) { - windowClass = w->classification; - windowNumber = w->number; - widget = &w->widgets[widgetIndex]; - } + WindowClass windowClass = WindowClass::Null; + rct_windownumber windowNumber = 0; + Widget* widget = nullptr; - InputWidgetOverChangeCheck(windowClass, windowNumber, widgetIndex); + if (w != nullptr) + { + windowClass = w->classification; + windowNumber = w->number; + widget = &w->widgets[widgetIndex]; + } - if (w != nullptr && widgetIndex != -1 && widget->type == WindowWidgetType::Scroll) - { - int32_t scroll_part, scrollId; - ScreenCoordsXY newScreenCoords; - WidgetScrollGetPart(*w, widget, screenCoords, newScreenCoords, &scroll_part, &scrollId); + InputWidgetOverChangeCheck(windowClass, windowNumber, widgetIndex); - if (scroll_part != SCROLL_PART_VIEW) - WindowTooltipClose(); + if (w != nullptr && widgetIndex != kWidgetIndexNull && widget->type == WindowWidgetType::Scroll) + { + int32_t scroll_part, scrollId; + ScreenCoordsXY newScreenCoords; + WidgetScrollGetPart(*w, widget, screenCoords, newScreenCoords, &scroll_part, &scrollId); + + if (scroll_part != SCROLL_PART_VIEW) + WindowTooltipClose(); + else + { + w->OnScrollMouseOver(scrollId, newScreenCoords); + InputUpdateTooltip(w, widgetIndex, screenCoords); + } + } else { - w->OnScrollMouseOver(scrollId, newScreenCoords); InputUpdateTooltip(w, widgetIndex, screenCoords); } } - else + + /** + * + * rct2: 0x006E9269 + */ + static void InputWidgetOverChangeCheck(WindowClass windowClass, rct_windownumber windowNumber, WidgetIndex widgetIndex) { - InputUpdateTooltip(w, widgetIndex, screenCoords); - } -} + // Prevents invalid widgets being clicked source of bug is elsewhere + if (widgetIndex == kWidgetIndexNull) + return; -/** - * - * rct2: 0x006E9269 - */ -static void InputWidgetOverChangeCheck(WindowClass windowClass, rct_windownumber windowNumber, WidgetIndex widgetIndex) -{ - // Prevents invalid widgets being clicked source of bug is elsewhere - if (widgetIndex == -1) - return; - - // Check if the widget that the cursor was over, has changed - if (windowClass != gHoverWidget.window_classification || windowNumber != gHoverWidget.window_number - || widgetIndex != gHoverWidget.widget_index) - { - // Invalidate last widget cursor was on if widget is a flat button - InputWidgetOverFlatbuttonInvalidate(); - - // Set new cursor over widget - gHoverWidget.window_classification = windowClass; - gHoverWidget.window_number = windowNumber; - gHoverWidget.widget_index = widgetIndex; - - // Invalidate new widget cursor is on if widget is a flat button - if (windowClass != WindowClass::Null) + // Check if the widget that the cursor was over, has changed + if (windowClass != gHoverWidget.window_classification || windowNumber != gHoverWidget.window_number + || widgetIndex != gHoverWidget.widget_index) + { + // Invalidate last widget cursor was on if widget is a flat button InputWidgetOverFlatbuttonInvalidate(); - } -} -/** - * Used to invalidate flat button widgets when the mouse leaves and enters them. This should be generalised so that all widgets - * can use this in the future. - */ -static void InputWidgetOverFlatbuttonInvalidate() -{ - auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); - WindowBase* w = windowMgr->FindByNumber(gHoverWidget.window_classification, gHoverWidget.window_number); - if (w != nullptr) - { - w->OnPrepareDraw(); - if (w->widgets[gHoverWidget.widget_index].type == WindowWidgetType::FlatBtn) - { - WidgetInvalidateByNumber(gHoverWidget.window_classification, gHoverWidget.window_number, gHoverWidget.widget_index); - } - } -} + // Set new cursor over widget + gHoverWidget.window_classification = windowClass; + gHoverWidget.window_number = windowNumber; + gHoverWidget.widget_index = widgetIndex; -/** - * - * rct2: 0x006E95F9 - */ -static void InputWidgetLeft(const ScreenCoordsXY& screenCoords, WindowBase* w, WidgetIndex widgetIndex) -{ - WindowClass windowClass = WindowClass::Null; - rct_windownumber windowNumber = 0; - - if (w != nullptr) - { - windowClass = w->classification; - windowNumber = w->number; - } - - WindowCloseByClass(WindowClass::Error); - WindowCloseByClass(WindowClass::Tooltip); - - // Window might have changed position in the list, therefore find it again - auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); - w = windowMgr->FindByNumber(windowClass, windowNumber); - if (w == nullptr) - return; - - w = WindowBringToFront(*w); - if (widgetIndex == -1) - return; - - if (windowClass != GetCurrentTextBox().window.classification || windowNumber != GetCurrentTextBox().window.number - || widgetIndex != GetCurrentTextBox().widget_index) - { - WindowCancelTextbox(); - } - - const auto& widget = w->widgets[widgetIndex]; - - switch (widget.type) - { - case WindowWidgetType::Frame: - case WindowWidgetType::Resize: - if (WindowCanResize(*w) - && (screenCoords.x >= w->windowPos.x + w->width - 19 && screenCoords.y >= w->windowPos.y + w->height - 19)) - InputWindowResizeBegin(*w, widgetIndex, screenCoords); - break; - case WindowWidgetType::Viewport: - _inputState = InputState::ViewportLeft; - gInputDragLast = screenCoords; - _dragWidget.window_classification = windowClass; - _dragWidget.window_number = windowNumber; - if (_inputFlags & INPUT_FLAG_TOOL_ACTIVE) - { - w = windowMgr->FindByNumber(gCurrentToolWidget.window_classification, gCurrentToolWidget.window_number); - if (w != nullptr) - { - InputSetFlag(INPUT_FLAG_4, true); - w->OnToolDown(gCurrentToolWidget.widget_index, screenCoords); - } - } - break; - case WindowWidgetType::Caption: - InputWindowPositionBegin(*w, widgetIndex, screenCoords); - break; - case WindowWidgetType::Scroll: - InputScrollBegin(*w, widgetIndex, screenCoords); - break; - case WindowWidgetType::Empty: - case WindowWidgetType::LabelCentred: - case WindowWidgetType::Label: - case WindowWidgetType::Groupbox: - case WindowWidgetType::ProgressBar: - case WindowWidgetType::Placeholder: - case WindowWidgetType::Last: - // Non-interactive widget type - break; - case WindowWidgetType::ImgBtn: - case WindowWidgetType::ColourBtn: - case WindowWidgetType::TrnBtn: - case WindowWidgetType::Tab: - case WindowWidgetType::FlatBtn: - case WindowWidgetType::Button: - case WindowWidgetType::TableHeader: - case WindowWidgetType::Spinner: - case WindowWidgetType::DropdownMenu: - case WindowWidgetType::CloseBox: - case WindowWidgetType::Checkbox: - case WindowWidgetType::TextBox: - case WindowWidgetType::Custom: - if (!WidgetIsDisabled(*w, widgetIndex)) - { - OpenRCT2::Audio::Play(OpenRCT2::Audio::SoundId::Click1, 0, w->windowPos.x + widget.midX()); - - // Set new cursor down widget - gPressedWidget.window_classification = windowClass; - gPressedWidget.window_number = windowNumber; - gPressedWidget.widget_index = widgetIndex; - _inputFlags |= INPUT_FLAG_WIDGET_PRESSED; - _inputState = InputState::WidgetPressed; - _clickRepeatTicks = gCurrentRealTimeTicks; - - WidgetInvalidateByNumber(windowClass, windowNumber, widgetIndex); - w->OnMouseDown(widgetIndex); - } - break; - } -} - -/** - * - * rct2: 0x006ED833 - */ -void ProcessMouseOver(const ScreenCoordsXY& screenCoords) -{ - CursorID cursorId = CursorID::Arrow; - auto ft = Formatter(); - ft.Add(STR_NONE); - SetMapTooltip(ft); - - auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); - WindowBase* window = windowMgr->FindFromPoint(screenCoords); - - if (window != nullptr) - { - WidgetIndex widgetId = windowMgr->FindWidgetFromPoint(*window, screenCoords); - if (widgetId != -1) - { - switch (window->widgets[widgetId].type) - { - case WindowWidgetType::Viewport: - if (!(_inputFlags & INPUT_FLAG_TOOL_ACTIVE)) - { - if (ViewportInteractionLeftOver(screenCoords)) - { - SetCursor(CursorID::HandPoint); - return; - } - break; - } - cursorId = static_cast(gCurrentToolId); - break; - - case WindowWidgetType::Frame: - case WindowWidgetType::Resize: - if (!(window->flags & WF_RESIZABLE)) - break; - - if (window->min_width == window->max_width && window->min_height == window->max_height) - break; - - if (screenCoords.x < window->windowPos.x + window->width - 0x13) - break; - - if (screenCoords.y < window->windowPos.y + window->height - 0x13) - break; - - cursorId = CursorID::DiagonalArrows; - break; - - case WindowWidgetType::Scroll: - { - int32_t output_scroll_area, scroll_id; - ScreenCoordsXY scrollCoords; - WidgetScrollGetPart( - *window, &window->widgets[widgetId], screenCoords, scrollCoords, &output_scroll_area, &scroll_id); - if (output_scroll_area != SCROLL_PART_VIEW) - { - cursorId = CursorID::Arrow; - break; - } - // Same as default but with scroll_x/y - cursorId = window->OnCursor(widgetId, scrollCoords, CursorID::Arrow); - if (cursorId == CursorID::Undefined) - cursorId = CursorID::Arrow; - break; - } - default: - cursorId = window->OnCursor(widgetId, screenCoords, CursorID::Arrow); - if (cursorId == CursorID::Undefined) - cursorId = CursorID::Arrow; - break; - } + // Invalidate new widget cursor is on if widget is a flat button + if (windowClass != WindowClass::Null) + InputWidgetOverFlatbuttonInvalidate(); } } - ViewportInteractionRightOver(screenCoords); - SetCursor(cursorId); -} - -/** - * - * rct2: 0x006ED801 - */ -void ProcessMouseTool(const ScreenCoordsXY& screenCoords) -{ - if (_inputFlags & INPUT_FLAG_TOOL_ACTIVE) + /** + * Used to invalidate flat button widgets when the mouse leaves and enters them. This should be generalised so that all + * widgets can use this in the future. + */ + static void InputWidgetOverFlatbuttonInvalidate() { auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); - WindowBase* w = windowMgr->FindByNumber(gCurrentToolWidget.window_classification, gCurrentToolWidget.window_number); - - if (w == nullptr) - ToolCancel(); - else if (InputGetState() != InputState::ViewportRight) - w->OnToolUpdate(gCurrentToolWidget.widget_index, screenCoords); - } -} - -const std::map kColourToTip = { - { COLOUR_BLACK, STR_COLOUR_BLACK_TIP }, - { COLOUR_GREY, STR_COLOUR_GREY_TIP }, - { COLOUR_WHITE, STR_COLOUR_WHITE_TIP }, - { COLOUR_DARK_PURPLE, STR_COLOUR_DARK_PURPLE_TIP }, - { COLOUR_LIGHT_PURPLE, STR_COLOUR_LIGHT_PURPLE_TIP }, - { COLOUR_BRIGHT_PURPLE, STR_COLOUR_BRIGHT_PURPLE_TIP }, - { COLOUR_DARK_BLUE, STR_COLOUR_DARK_BLUE_TIP }, - { COLOUR_LIGHT_BLUE, STR_COLOUR_LIGHT_BLUE_TIP }, - { COLOUR_ICY_BLUE, STR_COLOUR_ICY_BLUE_TIP }, - { COLOUR_TEAL, STR_COLOUR_TEAL_TIP }, - { COLOUR_AQUAMARINE, STR_COLOUR_AQUAMARINE_TIP }, - { COLOUR_SATURATED_GREEN, STR_COLOUR_SATURATED_GREEN_TIP }, - { COLOUR_DARK_GREEN, STR_COLOUR_DARK_GREEN_TIP }, - { COLOUR_MOSS_GREEN, STR_COLOUR_MOSS_GREEN_TIP }, - { COLOUR_BRIGHT_GREEN, STR_COLOUR_BRIGHT_GREEN_TIP }, - { COLOUR_OLIVE_GREEN, STR_COLOUR_OLIVE_GREEN_TIP }, - { COLOUR_DARK_OLIVE_GREEN, STR_COLOUR_DARK_OLIVE_GREEN_TIP }, - { COLOUR_BRIGHT_YELLOW, STR_COLOUR_BRIGHT_YELLOW_TIP }, - { COLOUR_YELLOW, STR_COLOUR_YELLOW_TIP }, - { COLOUR_DARK_YELLOW, STR_COLOUR_DARK_YELLOW_TIP }, - { COLOUR_LIGHT_ORANGE, STR_COLOUR_LIGHT_ORANGE_TIP }, - { COLOUR_DARK_ORANGE, STR_COLOUR_DARK_ORANGE_TIP }, - { COLOUR_LIGHT_BROWN, STR_COLOUR_LIGHT_BROWN_TIP }, - { COLOUR_SATURATED_BROWN, STR_COLOUR_SATURATED_BROWN_TIP }, - { COLOUR_DARK_BROWN, STR_COLOUR_DARK_BROWN_TIP }, - { COLOUR_SALMON_PINK, STR_COLOUR_SALMON_PINK_TIP }, - { COLOUR_BORDEAUX_RED, STR_COLOUR_BORDEAUX_RED_TIP }, - { COLOUR_SATURATED_RED, STR_COLOUR_SATURATED_RED_TIP }, - { COLOUR_BRIGHT_RED, STR_COLOUR_BRIGHT_RED_TIP }, - { COLOUR_DARK_PINK, STR_COLOUR_DARK_PINK_TIP }, - { COLOUR_BRIGHT_PINK, STR_COLOUR_BRIGHT_PINK_TIP }, - { COLOUR_LIGHT_PINK, STR_COLOUR_LIGHT_PINK_TIP }, - { COLOUR_DARK_OLIVE_DARK, STR_COLOUR_DARK_OLIVE_DARK_TIP }, - { COLOUR_DARK_OLIVE_LIGHT, STR_COLOUR_DARK_OLIVE_LIGHT_TIP }, - { COLOUR_SATURATED_BROWN_LIGHT, STR_COLOUR_SATURATED_BROWN_LIGHT_TIP }, - { COLOUR_BORDEAUX_RED_DARK, STR_COLOUR_BORDEAUX_RED_DARK_TIP }, - { COLOUR_BORDEAUX_RED_LIGHT, STR_COLOUR_BORDEAUX_RED_LIGHT_TIP }, - { COLOUR_GRASS_GREEN_DARK, STR_COLOUR_GRASS_GREEN_DARK_TIP }, - { COLOUR_GRASS_GREEN_LIGHT, STR_COLOUR_GRASS_GREEN_LIGHT_TIP }, - { COLOUR_OLIVE_DARK, STR_COLOUR_OLIVE_DARK_TIP }, - { COLOUR_OLIVE_LIGHT, STR_COLOUR_OLIVE_LIGHT_TIP }, - { COLOUR_SATURATED_GREEN_LIGHT, STR_COLOUR_SATURATED_GREEN_LIGHT_TIP }, - { COLOUR_TAN_DARK, STR_COLOUR_TAN_DARK_TIP }, - { COLOUR_TAN_LIGHT, STR_COLOUR_TAN_LIGHT_TIP }, - { COLOUR_DULL_PURPLE_LIGHT, STR_COLOUR_DULL_PURPLE_LIGHT_TIP }, - { COLOUR_DULL_GREEN_DARK, STR_COLOUR_DULL_GREEN_DARK_TIP }, - { COLOUR_DULL_GREEN_LIGHT, STR_COLOUR_DULL_GREEN_LIGHT_TIP }, - { COLOUR_SATURATED_PURPLE_DARK, STR_COLOUR_SATURATED_PURPLE_DARK_TIP }, - { COLOUR_SATURATED_PURPLE_LIGHT, STR_COLOUR_SATURATED_PURPLE_LIGHT_TIP }, - { COLOUR_ORANGE_LIGHT, STR_COLOUR_ORANGE_LIGHT_TIP }, - { COLOUR_AQUA_DARK, STR_COLOUR_AQUA_DARK_TIP }, - { COLOUR_MAGENTA_LIGHT, STR_COLOUR_MAGENTA_LIGHT_TIP }, - { COLOUR_DULL_BROWN_DARK, STR_COLOUR_DULL_BROWN_DARK_TIP }, - { COLOUR_DULL_BROWN_LIGHT, STR_COLOUR_DULL_BROWN_LIGHT_TIP }, - { COLOUR_INVISIBLE, STR_COLOUR_INVISIBLE_TIP }, - { COLOUR_VOID, STR_COLOUR_VOID_TIP }, -}; - -/** - * - * rct2: 0x006E8DA7 - */ -void InputStateWidgetPressed( - const ScreenCoordsXY& screenCoords, MouseState state, WidgetIndex widgetIndex, WindowBase* w, Widget* widget) -{ - WindowClass cursor_w_class; - rct_windownumber cursor_w_number; - cursor_w_class = gPressedWidget.window_classification; - cursor_w_number = gPressedWidget.window_number; - WidgetIndex cursor_widgetIndex = gPressedWidget.widget_index; - - auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); - WindowBase* cursor_w = windowMgr->FindByNumber(cursor_w_class, cursor_w_number); - if (cursor_w == nullptr) - { - _inputState = InputState::Reset; - return; - } - - if (w != nullptr && state == MouseState::LeftRelease) - { - if (w->widgets[widgetIndex].type == WindowWidgetType::CloseBox && cursor_w_class == w->classification - && cursor_w_number == w->number && widgetIndex == cursor_widgetIndex) + WindowBase* w = windowMgr->FindByNumber(gHoverWidget.window_classification, gHoverWidget.window_number); + if (w != nullptr) { - auto& im = GetInputManager(); - if (im.IsModifierKeyPressed(ModifierKey::shift)) + w->OnPrepareDraw(); + if (w->widgets[gHoverWidget.widget_index].type == WindowWidgetType::FlatBtn) { - gLastCloseModifier.window.number = w->number; - gLastCloseModifier.window.classification = w->classification; - gLastCloseModifier.modifier = CloseWindowModifier::Shift; - } - else if (im.IsModifierKeyPressed(ModifierKey::ctrl)) - { - gLastCloseModifier.window.number = w->number; - gLastCloseModifier.window.classification = w->classification; - gLastCloseModifier.modifier = CloseWindowModifier::Control; + WidgetInvalidateByNumber( + gHoverWidget.window_classification, gHoverWidget.window_number, gHoverWidget.widget_index); } } } - switch (state) + /** + * + * rct2: 0x006E95F9 + */ + static void InputWidgetLeft(const ScreenCoordsXY& screenCoords, WindowBase* w, WidgetIndex widgetIndex) { - case MouseState::Released: - if (w == nullptr || cursor_w_class != w->classification || cursor_w_number != w->number - || widgetIndex != cursor_widgetIndex) + WindowClass windowClass = WindowClass::Null; + rct_windownumber windowNumber = 0; + + if (w != nullptr) + { + windowClass = w->classification; + windowNumber = w->number; + } + + WindowCloseByClass(WindowClass::Error); + WindowCloseByClass(WindowClass::Tooltip); + + // Window might have changed position in the list, therefore find it again + auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); + w = windowMgr->FindByNumber(windowClass, windowNumber); + if (w == nullptr) + return; + + w = WindowBringToFront(*w); + if (widgetIndex == kWidgetIndexNull) + return; + + if (windowClass != GetCurrentTextBox().window.classification || windowNumber != GetCurrentTextBox().window.number + || widgetIndex != GetCurrentTextBox().widget_index) + { + WindowCancelTextbox(); + } + + const auto& widget = w->widgets[widgetIndex]; + + switch (widget.type) + { + case WindowWidgetType::Frame: + case WindowWidgetType::Resize: + if (WindowCanResize(*w) + && (screenCoords.x >= w->windowPos.x + w->width - 19 && screenCoords.y >= w->windowPos.y + w->height - 19)) + InputWindowResizeBegin(*w, widgetIndex, screenCoords); break; - - if (WidgetIsDisabled(*w, widgetIndex)) - break; - - // If this variable is non-zero then its the last tick the mouse down event was fired. - if (_clickRepeatTicks.has_value()) - { - // The initial amount of time in ticks to wait until the first click repeat. - constexpr auto ticksUntilRepeats = 16U; - - // The amount of ticks between each click repeat. - constexpr auto eventDelayInTicks = 3U; - - // The amount of ticks since the last click repeat. - const auto clickRepeatsDelta = gCurrentRealTimeTicks - _clickRepeatTicks.value(); - - // Handle click repeat, only start this when at least 16 ticks elapsed. - if (clickRepeatsDelta >= ticksUntilRepeats && (clickRepeatsDelta & eventDelayInTicks) == 0) + case WindowWidgetType::Viewport: + _inputState = InputState::ViewportLeft; + gInputDragLast = screenCoords; + _dragWidget.window_classification = windowClass; + _dragWidget.window_number = windowNumber; + if (_inputFlags & INPUT_FLAG_TOOL_ACTIVE) { - if (WidgetIsHoldable(*w, widgetIndex)) + w = windowMgr->FindByNumber(gCurrentToolWidget.window_classification, gCurrentToolWidget.window_number); + if (w != nullptr) { - w->OnMouseDown(widgetIndex); + InputSetFlag(INPUT_FLAG_4, true); + w->OnToolDown(gCurrentToolWidget.widget_index, screenCoords); } + } + break; + case WindowWidgetType::Caption: + InputWindowPositionBegin(*w, widgetIndex, screenCoords); + break; + case WindowWidgetType::Scroll: + InputScrollBegin(*w, widgetIndex, screenCoords); + break; + case WindowWidgetType::Empty: + case WindowWidgetType::LabelCentred: + case WindowWidgetType::Label: + case WindowWidgetType::Groupbox: + case WindowWidgetType::ProgressBar: + case WindowWidgetType::Placeholder: + // Non-interactive widget type + break; + case WindowWidgetType::ImgBtn: + case WindowWidgetType::ColourBtn: + case WindowWidgetType::TrnBtn: + case WindowWidgetType::Tab: + case WindowWidgetType::FlatBtn: + case WindowWidgetType::Button: + case WindowWidgetType::TableHeader: + case WindowWidgetType::Spinner: + case WindowWidgetType::DropdownMenu: + case WindowWidgetType::CloseBox: + case WindowWidgetType::Checkbox: + case WindowWidgetType::TextBox: + case WindowWidgetType::Custom: + if (!WidgetIsDisabled(*w, widgetIndex)) + { + OpenRCT2::Audio::Play(OpenRCT2::Audio::SoundId::Click1, 0, w->windowPos.x + widget.midX()); - // Subtract initial delay from here on we want the event each third tick. - _clickRepeatTicks = gCurrentRealTimeTicks - ticksUntilRepeats; + // Set new cursor down widget + gPressedWidget.window_classification = windowClass; + gPressedWidget.window_number = windowNumber; + gPressedWidget.widget_index = widgetIndex; + _inputFlags |= INPUT_FLAG_WIDGET_PRESSED; + _inputState = InputState::WidgetPressed; + _clickRepeatTicks = gCurrentRealTimeTicks; + + WidgetInvalidateByNumber(windowClass, windowNumber, widgetIndex); + w->OnMouseDown(widgetIndex); + } + break; + } + } + + /** + * + * rct2: 0x006ED833 + */ + void ProcessMouseOver(const ScreenCoordsXY& screenCoords) + { + CursorID cursorId = CursorID::Arrow; + auto ft = Formatter(); + ft.Add(STR_NONE); + SetMapTooltip(ft); + + auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); + WindowBase* window = windowMgr->FindFromPoint(screenCoords); + + if (window != nullptr) + { + WidgetIndex widgetId = windowMgr->FindWidgetFromPoint(*window, screenCoords); + if (widgetId != kWidgetIndexNull) + { + switch (window->widgets[widgetId].type) + { + case WindowWidgetType::Viewport: + if (!(_inputFlags & INPUT_FLAG_TOOL_ACTIVE)) + { + if (ViewportInteractionLeftOver(screenCoords)) + { + SetCursor(CursorID::HandPoint); + return; + } + break; + } + cursorId = static_cast(gCurrentToolId); + break; + + case WindowWidgetType::Frame: + case WindowWidgetType::Resize: + if (!(window->flags & WF_RESIZABLE)) + break; + + if (window->min_width == window->max_width && window->min_height == window->max_height) + break; + + if (screenCoords.x < window->windowPos.x + window->width - 0x13) + break; + + if (screenCoords.y < window->windowPos.y + window->height - 0x13) + break; + + cursorId = CursorID::DiagonalArrows; + break; + + case WindowWidgetType::Scroll: + { + int32_t output_scroll_area, scroll_id; + ScreenCoordsXY scrollCoords; + WidgetScrollGetPart( + *window, &window->widgets[widgetId], screenCoords, scrollCoords, &output_scroll_area, &scroll_id); + if (output_scroll_area != SCROLL_PART_VIEW) + { + cursorId = CursorID::Arrow; + break; + } + // Same as default but with scroll_x/y + cursorId = window->OnCursor(widgetId, scrollCoords, CursorID::Arrow); + if (cursorId == CursorID::Undefined) + cursorId = CursorID::Arrow; + break; + } + default: + cursorId = window->OnCursor(widgetId, screenCoords, CursorID::Arrow); + if (cursorId == CursorID::Undefined) + cursorId = CursorID::Arrow; + break; } } + } - if (_inputFlags & INPUT_FLAG_WIDGET_PRESSED) + ViewportInteractionRightOver(screenCoords); + SetCursor(cursorId); + } + + /** + * + * rct2: 0x006ED801 + */ + void ProcessMouseTool(const ScreenCoordsXY& screenCoords) + { + if (_inputFlags & INPUT_FLAG_TOOL_ACTIVE) + { + auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); + WindowBase* w = windowMgr->FindByNumber(gCurrentToolWidget.window_classification, gCurrentToolWidget.window_number); + + if (w == nullptr) + ToolCancel(); + else if (InputGetState() != InputState::ViewportRight) + w->OnToolUpdate(gCurrentToolWidget.widget_index, screenCoords); + } + } + + const std::map kColourToTip = { + { COLOUR_BLACK, STR_COLOUR_BLACK_TIP }, + { COLOUR_GREY, STR_COLOUR_GREY_TIP }, + { COLOUR_WHITE, STR_COLOUR_WHITE_TIP }, + { COLOUR_DARK_PURPLE, STR_COLOUR_DARK_PURPLE_TIP }, + { COLOUR_LIGHT_PURPLE, STR_COLOUR_LIGHT_PURPLE_TIP }, + { COLOUR_BRIGHT_PURPLE, STR_COLOUR_BRIGHT_PURPLE_TIP }, + { COLOUR_DARK_BLUE, STR_COLOUR_DARK_BLUE_TIP }, + { COLOUR_LIGHT_BLUE, STR_COLOUR_LIGHT_BLUE_TIP }, + { COLOUR_ICY_BLUE, STR_COLOUR_ICY_BLUE_TIP }, + { COLOUR_TEAL, STR_COLOUR_TEAL_TIP }, + { COLOUR_AQUAMARINE, STR_COLOUR_AQUAMARINE_TIP }, + { COLOUR_SATURATED_GREEN, STR_COLOUR_SATURATED_GREEN_TIP }, + { COLOUR_DARK_GREEN, STR_COLOUR_DARK_GREEN_TIP }, + { COLOUR_MOSS_GREEN, STR_COLOUR_MOSS_GREEN_TIP }, + { COLOUR_BRIGHT_GREEN, STR_COLOUR_BRIGHT_GREEN_TIP }, + { COLOUR_OLIVE_GREEN, STR_COLOUR_OLIVE_GREEN_TIP }, + { COLOUR_DARK_OLIVE_GREEN, STR_COLOUR_DARK_OLIVE_GREEN_TIP }, + { COLOUR_BRIGHT_YELLOW, STR_COLOUR_BRIGHT_YELLOW_TIP }, + { COLOUR_YELLOW, STR_COLOUR_YELLOW_TIP }, + { COLOUR_DARK_YELLOW, STR_COLOUR_DARK_YELLOW_TIP }, + { COLOUR_LIGHT_ORANGE, STR_COLOUR_LIGHT_ORANGE_TIP }, + { COLOUR_DARK_ORANGE, STR_COLOUR_DARK_ORANGE_TIP }, + { COLOUR_LIGHT_BROWN, STR_COLOUR_LIGHT_BROWN_TIP }, + { COLOUR_SATURATED_BROWN, STR_COLOUR_SATURATED_BROWN_TIP }, + { COLOUR_DARK_BROWN, STR_COLOUR_DARK_BROWN_TIP }, + { COLOUR_SALMON_PINK, STR_COLOUR_SALMON_PINK_TIP }, + { COLOUR_BORDEAUX_RED, STR_COLOUR_BORDEAUX_RED_TIP }, + { COLOUR_SATURATED_RED, STR_COLOUR_SATURATED_RED_TIP }, + { COLOUR_BRIGHT_RED, STR_COLOUR_BRIGHT_RED_TIP }, + { COLOUR_DARK_PINK, STR_COLOUR_DARK_PINK_TIP }, + { COLOUR_BRIGHT_PINK, STR_COLOUR_BRIGHT_PINK_TIP }, + { COLOUR_LIGHT_PINK, STR_COLOUR_LIGHT_PINK_TIP }, + { COLOUR_DARK_OLIVE_DARK, STR_COLOUR_DARK_OLIVE_DARK_TIP }, + { COLOUR_DARK_OLIVE_LIGHT, STR_COLOUR_DARK_OLIVE_LIGHT_TIP }, + { COLOUR_SATURATED_BROWN_LIGHT, STR_COLOUR_SATURATED_BROWN_LIGHT_TIP }, + { COLOUR_BORDEAUX_RED_DARK, STR_COLOUR_BORDEAUX_RED_DARK_TIP }, + { COLOUR_BORDEAUX_RED_LIGHT, STR_COLOUR_BORDEAUX_RED_LIGHT_TIP }, + { COLOUR_GRASS_GREEN_DARK, STR_COLOUR_GRASS_GREEN_DARK_TIP }, + { COLOUR_GRASS_GREEN_LIGHT, STR_COLOUR_GRASS_GREEN_LIGHT_TIP }, + { COLOUR_OLIVE_DARK, STR_COLOUR_OLIVE_DARK_TIP }, + { COLOUR_OLIVE_LIGHT, STR_COLOUR_OLIVE_LIGHT_TIP }, + { COLOUR_SATURATED_GREEN_LIGHT, STR_COLOUR_SATURATED_GREEN_LIGHT_TIP }, + { COLOUR_TAN_DARK, STR_COLOUR_TAN_DARK_TIP }, + { COLOUR_TAN_LIGHT, STR_COLOUR_TAN_LIGHT_TIP }, + { COLOUR_DULL_PURPLE_LIGHT, STR_COLOUR_DULL_PURPLE_LIGHT_TIP }, + { COLOUR_DULL_GREEN_DARK, STR_COLOUR_DULL_GREEN_DARK_TIP }, + { COLOUR_DULL_GREEN_LIGHT, STR_COLOUR_DULL_GREEN_LIGHT_TIP }, + { COLOUR_SATURATED_PURPLE_DARK, STR_COLOUR_SATURATED_PURPLE_DARK_TIP }, + { COLOUR_SATURATED_PURPLE_LIGHT, STR_COLOUR_SATURATED_PURPLE_LIGHT_TIP }, + { COLOUR_ORANGE_LIGHT, STR_COLOUR_ORANGE_LIGHT_TIP }, + { COLOUR_AQUA_DARK, STR_COLOUR_AQUA_DARK_TIP }, + { COLOUR_MAGENTA_LIGHT, STR_COLOUR_MAGENTA_LIGHT_TIP }, + { COLOUR_DULL_BROWN_DARK, STR_COLOUR_DULL_BROWN_DARK_TIP }, + { COLOUR_DULL_BROWN_LIGHT, STR_COLOUR_DULL_BROWN_LIGHT_TIP }, + { COLOUR_INVISIBLE, STR_COLOUR_INVISIBLE_TIP }, + { COLOUR_VOID, STR_COLOUR_VOID_TIP }, + }; + + /** + * + * rct2: 0x006E8DA7 + */ + void InputStateWidgetPressed( + const ScreenCoordsXY& screenCoords, MouseState state, WidgetIndex widgetIndex, WindowBase* w, Widget* widget) + { + WindowClass cursor_w_class; + rct_windownumber cursor_w_number; + cursor_w_class = gPressedWidget.window_classification; + cursor_w_number = gPressedWidget.window_number; + WidgetIndex cursor_widgetIndex = gPressedWidget.widget_index; + + auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); + WindowBase* cursor_w = windowMgr->FindByNumber(cursor_w_class, cursor_w_number); + if (cursor_w == nullptr) + { + _inputState = InputState::Reset; + return; + } + + if (w != nullptr && state == MouseState::LeftRelease) + { + if (w->widgets[widgetIndex].type == WindowWidgetType::CloseBox && cursor_w_class == w->classification + && cursor_w_number == w->number && widgetIndex == cursor_widgetIndex) { + auto& im = GetInputManager(); + if (im.IsModifierKeyPressed(ModifierKey::shift)) + { + gLastCloseModifier.window.number = w->number; + gLastCloseModifier.window.classification = w->classification; + gLastCloseModifier.modifier = CloseWindowModifier::Shift; + } + else if (im.IsModifierKeyPressed(ModifierKey::ctrl)) + { + gLastCloseModifier.window.number = w->number; + gLastCloseModifier.window.classification = w->classification; + gLastCloseModifier.modifier = CloseWindowModifier::Control; + } + } + } + + switch (state) + { + case MouseState::Released: + if (w == nullptr || cursor_w_class != w->classification || cursor_w_number != w->number + || widgetIndex != cursor_widgetIndex) + break; + + if (WidgetIsDisabled(*w, widgetIndex)) + break; + + // If this variable is non-zero then its the last tick the mouse down event was fired. + if (_clickRepeatTicks.has_value()) + { + // The initial amount of time in ticks to wait until the first click repeat. + constexpr auto ticksUntilRepeats = 16U; + + // The amount of ticks between each click repeat. + constexpr auto eventDelayInTicks = 3U; + + // The amount of ticks since the last click repeat. + const auto clickRepeatsDelta = gCurrentRealTimeTicks - _clickRepeatTicks.value(); + + // Handle click repeat, only start this when at least 16 ticks elapsed. + if (clickRepeatsDelta >= ticksUntilRepeats && (clickRepeatsDelta & eventDelayInTicks) == 0) + { + if (WidgetIsHoldable(*w, widgetIndex)) + { + w->OnMouseDown(widgetIndex); + } + + // Subtract initial delay from here on we want the event each third tick. + _clickRepeatTicks = gCurrentRealTimeTicks - ticksUntilRepeats; + } + } + + if (_inputFlags & INPUT_FLAG_WIDGET_PRESSED) + { + if (_inputState == InputState::DropdownActive) + { + gDropdownHighlightedIndex = gDropdownDefaultIndex; + WindowInvalidateByClass(WindowClass::Dropdown); + } + return; + } + + _inputFlags |= INPUT_FLAG_WIDGET_PRESSED; + WidgetInvalidateByNumber(cursor_w_class, cursor_w_number, widgetIndex); + return; + case MouseState::LeftRelease: + case MouseState::RightPress: if (_inputState == InputState::DropdownActive) { - gDropdownHighlightedIndex = gDropdownDefaultIndex; - WindowInvalidateByClass(WindowClass::Dropdown); - } - return; - } - - _inputFlags |= INPUT_FLAG_WIDGET_PRESSED; - WidgetInvalidateByNumber(cursor_w_class, cursor_w_number, widgetIndex); - return; - case MouseState::LeftRelease: - case MouseState::RightPress: - if (_inputState == InputState::DropdownActive) - { - if (w != nullptr) - { - auto wClass = w->classification; - auto wNumber = w->number; - int32_t dropdown_index = 0; - bool dropdownCleanup = false; - - if (w->classification == WindowClass::Dropdown) + if (w != nullptr) { - dropdown_index = DropdownIndexFromPoint(screenCoords, w); - dropdownCleanup = dropdown_index == -1 - || (dropdown_index < Dropdown::ItemsMaxSize && Dropdown::IsDisabled(dropdown_index)) - || gDropdownItems[dropdown_index].IsSeparator(); - w = nullptr; // To be closed right next - } - else - { - if (cursor_w_class != w->classification || cursor_w_number != w->number - || widgetIndex != cursor_widgetIndex) + auto wClass = w->classification; + auto wNumber = w->number; + int32_t dropdown_index = 0; + bool dropdownCleanup = false; + + if (w->classification == WindowClass::Dropdown) { - dropdownCleanup = true; + dropdown_index = DropdownIndexFromPoint(screenCoords, w); + dropdownCleanup = dropdown_index == -1 + || (dropdown_index < Dropdown::ItemsMaxSize && Dropdown::IsDisabled(dropdown_index)) + || gDropdownItems[dropdown_index].IsSeparator(); + w = nullptr; // To be closed right next } else { - dropdown_index = -1; - if (_inputFlags & INPUT_FLAG_DROPDOWN_STAY_OPEN) + if (cursor_w_class != w->classification || cursor_w_number != w->number + || widgetIndex != cursor_widgetIndex) { - if (!(_inputFlags & INPUT_FLAG_DROPDOWN_MOUSE_UP)) + dropdownCleanup = true; + } + else + { + dropdown_index = -1; + if (_inputFlags & INPUT_FLAG_DROPDOWN_STAY_OPEN) { - _inputFlags |= INPUT_FLAG_DROPDOWN_MOUSE_UP; - return; + if (!(_inputFlags & INPUT_FLAG_DROPDOWN_MOUSE_UP)) + { + _inputFlags |= INPUT_FLAG_DROPDOWN_MOUSE_UP; + return; + } } } } - } - WindowCloseByClass(WindowClass::Dropdown); + WindowCloseByClass(WindowClass::Dropdown); - if (dropdownCleanup) - { - // Update w as it will be invalid after closing the dropdown window - w = windowMgr->FindByNumber(wClass, wNumber); - } - else - { - cursor_w = windowMgr->FindByNumber(cursor_w_class, cursor_w_number); - if (_inputFlags & INPUT_FLAG_WIDGET_PRESSED) + if (dropdownCleanup) { - _inputFlags &= ~INPUT_FLAG_WIDGET_PRESSED; - WidgetInvalidateByNumber(cursor_w_class, cursor_w_number, cursor_widgetIndex); + // Update w as it will be invalid after closing the dropdown window + w = windowMgr->FindByNumber(wClass, wNumber); } - - _inputState = InputState::Normal; - gTooltipCloseTimeout = 0; - gTooltipWidget.widget_index = cursor_widgetIndex; - gTooltipWidget.window_classification = cursor_w_class; - gTooltipWidget.window_number = cursor_w_number; - - if (dropdown_index == -1) + else { - if (!Dropdown::IsDisabled(gDropdownDefaultIndex)) + cursor_w = windowMgr->FindByNumber(cursor_w_class, cursor_w_number); + if (_inputFlags & INPUT_FLAG_WIDGET_PRESSED) { - dropdown_index = gDropdownDefaultIndex; + _inputFlags &= ~INPUT_FLAG_WIDGET_PRESSED; + WidgetInvalidateByNumber(cursor_w_class, cursor_w_number, cursor_widgetIndex); } + + _inputState = InputState::Normal; + gTooltipCloseTimeout = 0; + gTooltipWidget.widget_index = cursor_widgetIndex; + gTooltipWidget.window_classification = cursor_w_class; + gTooltipWidget.window_number = cursor_w_number; + + if (dropdown_index == -1) + { + if (!Dropdown::IsDisabled(gDropdownDefaultIndex)) + { + dropdown_index = gDropdownDefaultIndex; + } + } + cursor_w->OnDropdown(cursor_widgetIndex, dropdown_index); } - cursor_w->OnDropdown(cursor_widgetIndex, dropdown_index); } } + + _inputState = InputState::Normal; + + if (state == MouseState::RightPress) + { + return; + } + + gTooltipCloseTimeout = 0; + gTooltipWidget.widget_index = cursor_widgetIndex; + + if (w == nullptr) + break; + + if (widget == nullptr) + break; + + { + int32_t mid_point_x = widget->midX() + w->windowPos.x; + OpenRCT2::Audio::Play(OpenRCT2::Audio::SoundId::Click2, 0, mid_point_x); + } + if (cursor_w_class != w->classification || cursor_w_number != w->number || widgetIndex != cursor_widgetIndex) + break; + + if (WidgetIsDisabled(*w, widgetIndex)) + break; + + WidgetInvalidateByNumber(cursor_w_class, cursor_w_number, widgetIndex); + w->OnMouseUp(widgetIndex); + return; + + default: + return; + } + + _clickRepeatTicks = std::nullopt; + if (_inputState != InputState::DropdownActive) + { + // Hold down widget and drag outside of area?? + if (_inputFlags & INPUT_FLAG_WIDGET_PRESSED) + { + _inputFlags &= ~INPUT_FLAG_WIDGET_PRESSED; + WidgetInvalidateByNumber(cursor_w_class, cursor_w_number, cursor_widgetIndex); } + return; + } + else if (gDropdownIsColour) + { + // This is ordinarily covered in InputWidgetOver but the dropdown with colours is a special case. + InputUpdateTooltip(w, widgetIndex, screenCoords); + } - _inputState = InputState::Normal; + gDropdownHighlightedIndex = -1; + WindowInvalidateByClass(WindowClass::Dropdown); + if (w == nullptr) + { + return; + } - if (state == MouseState::RightPress) + if (w->classification == WindowClass::Dropdown) + { + int32_t dropdown_index = DropdownIndexFromPoint(screenCoords, w); + if (dropdown_index == -1) { return; } - gTooltipCloseTimeout = 0; - gTooltipWidget.widget_index = cursor_widgetIndex; - - if (w == nullptr) - break; - - if (widget == nullptr) - break; - + if (gDropdownIsColour && gDropdownLastColourHover != dropdown_index) { - int32_t mid_point_x = widget->midX() + w->windowPos.x; - OpenRCT2::Audio::Play(OpenRCT2::Audio::SoundId::Click2, 0, mid_point_x); + gDropdownLastColourHover = dropdown_index; + WindowTooltipClose(); + + WindowTooltipShow( + OpenRCT2String{ kColourToTip.at(ColourDropDownIndexToColour(dropdown_index)), {} }, screenCoords); } - if (cursor_w_class != w->classification || cursor_w_number != w->number || widgetIndex != cursor_widgetIndex) - break; - if (WidgetIsDisabled(*w, widgetIndex)) - break; - - WidgetInvalidateByNumber(cursor_w_class, cursor_w_number, widgetIndex); - w->OnMouseUp(widgetIndex); - return; - - default: - return; - } - - _clickRepeatTicks = std::nullopt; - if (_inputState != InputState::DropdownActive) - { - // Hold down widget and drag outside of area?? - if (_inputFlags & INPUT_FLAG_WIDGET_PRESSED) - { - _inputFlags &= ~INPUT_FLAG_WIDGET_PRESSED; - WidgetInvalidateByNumber(cursor_w_class, cursor_w_number, cursor_widgetIndex); - } - return; - } - else if (gDropdownIsColour) - { - // This is ordinarily covered in InputWidgetOver but the dropdown with colours is a special case. - InputUpdateTooltip(w, widgetIndex, screenCoords); - } - - gDropdownHighlightedIndex = -1; - WindowInvalidateByClass(WindowClass::Dropdown); - if (w == nullptr) - { - return; - } - - if (w->classification == WindowClass::Dropdown) - { - int32_t dropdown_index = DropdownIndexFromPoint(screenCoords, w); - if (dropdown_index == -1) - { - return; - } - - if (gDropdownIsColour && gDropdownLastColourHover != dropdown_index) - { - gDropdownLastColourHover = dropdown_index; - WindowTooltipClose(); - - WindowTooltipShow(OpenRCT2String{ kColourToTip.at(ColourDropDownIndexToColour(dropdown_index)), {} }, screenCoords); - } - - if (dropdown_index < Dropdown::ItemsMaxSize && Dropdown::IsDisabled(dropdown_index)) - { - return; - } - - if (gDropdownItems[dropdown_index].IsSeparator()) - { - return; - } - - gDropdownHighlightedIndex = dropdown_index; - WindowInvalidateByClass(WindowClass::Dropdown); - } - else - { - gDropdownLastColourHover = -1; - WindowTooltipClose(); - } -} - -static void InputUpdateTooltip(WindowBase* w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords) -{ - if (gTooltipWidget.window_classification == WindowClass::Null) - { - if (gTooltipCursor == screenCoords) - { - if (gCurrentRealTimeTicks >= _tooltipNotShownTimeout && w != nullptr && WidgetIsVisible(*w, widgetIndex)) + if (dropdown_index < Dropdown::ItemsMaxSize && Dropdown::IsDisabled(dropdown_index)) { - gTooltipCloseTimeout = gCurrentRealTimeTicks + 8000; - WindowTooltipOpen(w, widgetIndex, screenCoords); + return; } + + if (gDropdownItems[dropdown_index].IsSeparator()) + { + return; + } + + gDropdownHighlightedIndex = dropdown_index; + WindowInvalidateByClass(WindowClass::Dropdown); } else { - ResetTooltipNotShown(); - } - - gTooltipCloseTimeout = gCurrentRealTimeTicks + 8000; - gTooltipCursor = screenCoords; - } - else - { - gTooltipCursor = screenCoords; - ResetTooltipNotShown(); - - if (w == nullptr || gTooltipWidget.window_classification != w->classification - || gTooltipWidget.window_number != w->number || gTooltipWidget.widget_index != widgetIndex - || !WidgetIsVisible(*w, widgetIndex)) - { + gDropdownLastColourHover = -1; WindowTooltipClose(); } + } - if (gCurrentRealTimeTicks >= gTooltipCloseTimeout) + static void InputUpdateTooltip(WindowBase* w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords) + { + if (gTooltipWidget.window_classification == WindowClass::Null) { - WindowCloseByClass(WindowClass::Tooltip); + if (gTooltipCursor == screenCoords) + { + if (gCurrentRealTimeTicks >= _tooltipNotShownTimeout && w != nullptr && WidgetIsVisible(*w, widgetIndex)) + { + gTooltipCloseTimeout = gCurrentRealTimeTicks + 8000; + WindowTooltipOpen(w, widgetIndex, screenCoords); + } + } + else + { + ResetTooltipNotShown(); + } + + gTooltipCloseTimeout = gCurrentRealTimeTicks + 8000; + gTooltipCursor = screenCoords; + } + else + { + gTooltipCursor = screenCoords; + ResetTooltipNotShown(); + + if (w == nullptr || gTooltipWidget.window_classification != w->classification + || gTooltipWidget.window_number != w->number || gTooltipWidget.widget_index != widgetIndex + || !WidgetIsVisible(*w, widgetIndex)) + { + WindowTooltipClose(); + } + + if (gCurrentRealTimeTicks >= gTooltipCloseTimeout) + { + WindowCloseByClass(WindowClass::Tooltip); + } } } -} #pragma endregion -/** - * - * rct2: 0x006ED990 - */ -void SetCursor(CursorID cursor_id) -{ - assert(cursor_id != CursorID::Undefined); - if (_inputState == InputState::Resizing) + /** + * + * rct2: 0x006ED990 + */ + void SetCursor(CursorID cursor_id) { - cursor_id = CursorID::DiagonalArrows; + assert(cursor_id != CursorID::Undefined); + if (_inputState == InputState::Resizing) + { + cursor_id = CursorID::DiagonalArrows; + } + ContextSetCurrentCursor(cursor_id); } - ContextSetCurrentCursor(cursor_id); -} -/** - * - * rct2: 0x006E876D - */ -void InvalidateScroll() -{ - auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); - WindowBase* w = windowMgr->FindByNumber(gPressedWidget.window_classification, gPressedWidget.window_number); - if (w != nullptr) + /** + * + * rct2: 0x006E876D + */ + void InvalidateScroll() { - // Reset to basic scroll - w->scrolls[_currentScrollIndex].flags &= 0xFF11; - WindowInvalidateByNumber(gPressedWidget.window_classification, gPressedWidget.window_number); + auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); + WindowBase* w = windowMgr->FindByNumber(gPressedWidget.window_classification, gPressedWidget.window_number); + if (w != nullptr) + { + // Reset to basic scroll + w->scrolls[_currentScrollIndex].flags &= 0xFF11; + WindowInvalidateByNumber(gPressedWidget.window_classification, gPressedWidget.window_number); + } } -} -/** - * rct2: 0x00406C96 - */ -void StoreMouseInput(MouseState state, const ScreenCoordsXY& screenCoords) -{ - uint32_t writeIndex = _mouseInputQueueWriteIndex; - uint32_t nextWriteIndex = (writeIndex + 1) % std::size(_mouseInputQueue); - - // Check if the queue is full - if (nextWriteIndex != _mouseInputQueueReadIndex) + /** + * rct2: 0x00406C96 + */ + void StoreMouseInput(MouseState state, const ScreenCoordsXY& screenCoords) { - RCTMouseData* item = &_mouseInputQueue[writeIndex]; - item->x = screenCoords.x; - item->y = screenCoords.y; - item->state = state; + uint32_t writeIndex = _mouseInputQueueWriteIndex; + uint32_t nextWriteIndex = (writeIndex + 1) % std::size(_mouseInputQueue); - _mouseInputQueueWriteIndex = nextWriteIndex; + // Check if the queue is full + if (nextWriteIndex != _mouseInputQueueReadIndex) + { + RCTMouseData* item = &_mouseInputQueue[writeIndex]; + item->x = screenCoords.x; + item->y = screenCoords.y; + item->state = state; + + _mouseInputQueueWriteIndex = nextWriteIndex; + } } -} -void GameHandleEdgeScroll() -{ - WindowBase* mainWindow; - int32_t scrollX, scrollY; - - mainWindow = WindowGetMain(); - if (mainWindow == nullptr) - return; - if ((mainWindow->flags & WF_NO_SCROLLING) || (gScreenFlags & (SCREEN_FLAGS_TRACK_MANAGER | SCREEN_FLAGS_TITLE_DEMO))) - return; - if (mainWindow->viewport == nullptr) - return; - if (!ContextHasFocus()) - return; - - scrollX = 0; - scrollY = 0; - - // Scroll left / right - const CursorState* cursorState = ContextGetCursorState(); - if (cursorState->position.x == 0) - scrollX = -1; - else if (cursorState->position.x >= ContextGetWidth() - 1) - scrollX = 1; - - // Scroll up / down - if (cursorState->position.y == 0) - scrollY = -1; - else if (cursorState->position.y >= ContextGetHeight() - 1) - scrollY = 1; - - InputScrollViewport(ScreenCoordsXY(scrollX, scrollY)); -} - -void InputScrollViewport(const ScreenCoordsXY& scrollScreenCoords) -{ - WindowBase* mainWindow = WindowGetMain(); - if (mainWindow == nullptr) - return; - - Viewport* viewport = mainWindow->viewport; - if (viewport == nullptr) - return; - - const int32_t speed = Config::Get().general.EdgeScrollingSpeed; - - int32_t multiplier = viewport->zoom.ApplyTo(speed); - int32_t dx = scrollScreenCoords.x * multiplier; - int32_t dy = scrollScreenCoords.y * multiplier; - - if (scrollScreenCoords.x != 0) + void GameHandleEdgeScroll() { - // Speed up scrolling horizontally when at the edge of the map - // so that the speed is consistent with vertical edge scrolling. - int32_t x = mainWindow->savedViewPos.x + viewport->ViewWidth() / 2 + dx; - int32_t y = mainWindow->savedViewPos.y + viewport->ViewHeight() / 2; - int32_t y_dy = mainWindow->savedViewPos.y + viewport->ViewHeight() / 2 + dy; + WindowBase* mainWindow; + int32_t scrollX, scrollY; - auto mapCoord = ViewportPosToMapPos({ x, y }, 0, viewport->rotation); - auto mapCoord_dy = ViewportPosToMapPos({ x, y_dy }, 0, viewport->rotation); + mainWindow = WindowGetMain(); + if (mainWindow == nullptr) + return; + if ((mainWindow->flags & WF_NO_SCROLLING) || (gScreenFlags & (SCREEN_FLAGS_TRACK_MANAGER | SCREEN_FLAGS_TITLE_DEMO))) + return; + if (mainWindow->viewport == nullptr) + return; + if (!ContextHasFocus()) + return; - // Check if we're crossing the boundary - // Clamp to the map minimum value - int32_t at_map_edge = 0; - int32_t at_map_edge_dy = 0; - if (mapCoord.x < kMapMinimumXY || mapCoord.y < kMapMinimumXY) - { - at_map_edge = 1; - } - if (mapCoord_dy.x < kMapMinimumXY || mapCoord_dy.y < kMapMinimumXY) - { - at_map_edge_dy = 1; - } + scrollX = 0; + scrollY = 0; - // Clamp to the map maximum value (scenario specific) - auto mapSizeMinus2 = GetMapSizeMinus2(); - if (mapCoord.x > mapSizeMinus2.x || mapCoord.y > mapSizeMinus2.y) - { - at_map_edge = 1; - } - if (mapCoord_dy.x > mapSizeMinus2.x || mapCoord_dy.y > mapSizeMinus2.y) - { - at_map_edge_dy = 1; - } + // Scroll left / right + const CursorState* cursorState = ContextGetCursorState(); + if (cursorState->position.x == 0) + scrollX = -1; + else if (cursorState->position.x >= ContextGetWidth() - 1) + scrollX = 1; - // If we crossed the boundary, multiply the distance by 2 - if (at_map_edge && at_map_edge_dy) - { - dx *= 2; - } + // Scroll up / down + if (cursorState->position.y == 0) + scrollY = -1; + else if (cursorState->position.y >= ContextGetHeight() - 1) + scrollY = 1; - mainWindow->savedViewPos.x += dx; - _inputFlags |= INPUT_FLAG_VIEWPORT_SCROLLING; + InputScrollViewport(ScreenCoordsXY(scrollX, scrollY)); } - if (scrollScreenCoords.y != 0) + + void InputScrollViewport(const ScreenCoordsXY& scrollScreenCoords) { - mainWindow->savedViewPos.y += dy; - _inputFlags |= INPUT_FLAG_VIEWPORT_SCROLLING; + WindowBase* mainWindow = WindowGetMain(); + if (mainWindow == nullptr) + return; + + Viewport* viewport = mainWindow->viewport; + if (viewport == nullptr) + return; + + const int32_t speed = Config::Get().general.EdgeScrollingSpeed; + + int32_t multiplier = viewport->zoom.ApplyTo(speed); + int32_t dx = scrollScreenCoords.x * multiplier; + int32_t dy = scrollScreenCoords.y * multiplier; + + if (scrollScreenCoords.x != 0) + { + // Speed up scrolling horizontally when at the edge of the map + // so that the speed is consistent with vertical edge scrolling. + int32_t x = mainWindow->savedViewPos.x + viewport->ViewWidth() / 2 + dx; + int32_t y = mainWindow->savedViewPos.y + viewport->ViewHeight() / 2; + int32_t y_dy = mainWindow->savedViewPos.y + viewport->ViewHeight() / 2 + dy; + + auto mapCoord = ViewportPosToMapPos({ x, y }, 0, viewport->rotation); + auto mapCoord_dy = ViewportPosToMapPos({ x, y_dy }, 0, viewport->rotation); + + // Check if we're crossing the boundary + // Clamp to the map minimum value + int32_t at_map_edge = 0; + int32_t at_map_edge_dy = 0; + if (mapCoord.x < kMapMinimumXY || mapCoord.y < kMapMinimumXY) + { + at_map_edge = 1; + } + if (mapCoord_dy.x < kMapMinimumXY || mapCoord_dy.y < kMapMinimumXY) + { + at_map_edge_dy = 1; + } + + // Clamp to the map maximum value (scenario specific) + auto mapSizeMinus2 = GetMapSizeMinus2(); + if (mapCoord.x > mapSizeMinus2.x || mapCoord.y > mapSizeMinus2.y) + { + at_map_edge = 1; + } + if (mapCoord_dy.x > mapSizeMinus2.x || mapCoord_dy.y > mapSizeMinus2.y) + { + at_map_edge_dy = 1; + } + + // If we crossed the boundary, multiply the distance by 2 + if (at_map_edge && at_map_edge_dy) + { + dx *= 2; + } + + mainWindow->savedViewPos.x += dx; + _inputFlags |= INPUT_FLAG_VIEWPORT_SCROLLING; + } + if (scrollScreenCoords.y != 0) + { + mainWindow->savedViewPos.y += dy; + _inputFlags |= INPUT_FLAG_VIEWPORT_SCROLLING; + } } -} +} // namespace OpenRCT2 diff --git a/src/openrct2-ui/input/MouseInput.h b/src/openrct2-ui/input/MouseInput.h index 14bfda2f66..4fe8a5e99b 100644 --- a/src/openrct2-ui/input/MouseInput.h +++ b/src/openrct2-ui/input/MouseInput.h @@ -11,21 +11,24 @@ #include -enum class MouseState : uint32_t +namespace OpenRCT2 { - Released, - LeftPress, - LeftRelease, - RightPress, - RightRelease -}; + enum class MouseState : uint32_t + { + Released, + LeftPress, + LeftRelease, + RightPress, + RightRelease + }; -extern ScreenCoordsXY gInputDragLast; + extern ScreenCoordsXY gInputDragLast; -void InputWindowPositionBegin(WindowBase& w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords); -void GameHandleInput(); -void GameHandleEdgeScroll(); + void InputWindowPositionBegin(WindowBase& w, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords); + void GameHandleInput(); + void GameHandleEdgeScroll(); -void StoreMouseInput(MouseState state, const ScreenCoordsXY& screenCoords); + void StoreMouseInput(MouseState state, const ScreenCoordsXY& screenCoords); -void InputScrollViewport(const ScreenCoordsXY& screenCoords); + void InputScrollViewport(const ScreenCoordsXY& screenCoords); +} // namespace OpenRCT2 diff --git a/src/openrct2-ui/interface/LandTool.h b/src/openrct2-ui/interface/LandTool.h index 936667197b..e7cac0c701 100644 --- a/src/openrct2-ui/interface/LandTool.h +++ b/src/openrct2-ui/interface/LandTool.h @@ -10,6 +10,7 @@ #pragma once #include +#include constexpr uint16_t kLandToolMinimumSize = 1; constexpr uint16_t kLandToolMaximumSize = 64; diff --git a/src/openrct2-ui/interface/Widget.cpp b/src/openrct2-ui/interface/Widget.cpp index 240b482fd6..50ef0d8234 100644 --- a/src/openrct2-ui/interface/Widget.cpp +++ b/src/openrct2-ui/interface/Widget.cpp @@ -9,6 +9,7 @@ #include "Widget.h" +#include #include #include #include @@ -939,9 +940,11 @@ namespace OpenRCT2::Ui int32_t* output_scroll_area, int32_t* scroll_id) { *scroll_id = 0; - for (Widget* iterator = w.widgets; iterator != widget; iterator++) + auto itLast = std::find_if( + w.widgets.begin(), w.widgets.end(), [&](auto& otherWidget) { return &otherWidget == widget; }); + for (auto it = w.widgets.begin(); it != itLast; it++) { - if (iterator->type == WindowWidgetType::Scroll) + if (it->type == WindowWidgetType::Scroll) { *scroll_id += 1; } @@ -1044,20 +1047,13 @@ namespace OpenRCT2::Ui Widget* GetWidgetByIndex(const WindowBase& w, WidgetIndex widgetIndex) { - // Make sure we don't go out of bounds if we are given a bad widget index - WidgetIndex index = 0; - for (auto* widget = w.widgets; widget->type != WindowWidgetType::Last; widget++) + if (widgetIndex >= w.widgets.size()) { - if (index == widgetIndex) - { - return widget; - } - index++; + LOG_ERROR("Widget index %i out of bounds for window class %u", widgetIndex, w.classification); } - LOG_ERROR("Widget index %i out of bounds for window class %u", widgetIndex, w.classification); - - return nullptr; + // FIXME: This const_cast is bad. + return const_cast(w.widgets.data() + widgetIndex); } static void SafeSetWidgetFlag(WindowBase& w, WidgetIndex widgetIndex, WidgetFlags mask, bool value) diff --git a/src/openrct2-ui/interface/Widget.h b/src/openrct2-ui/interface/Widget.h index 8a085ffae5..1442f79f1f 100644 --- a/src/openrct2-ui/interface/Widget.h +++ b/src/openrct2-ui/interface/Widget.h @@ -30,7 +30,6 @@ namespace OpenRCT2::Ui ImageId GetColourButtonImage(colour_t colour); Widget* GetWidgetByIndex(const WindowBase& w, WidgetIndex widgetIndex); - constexpr auto kWidgetsEnd = Widget{ WindowWidgetType::Last, 0, 0, 0, 0, 0, 0, 0 }; constexpr uint32_t kWidgetContentEmpty = 0xFFFFFFFF; constexpr auto kBarBlink = (1u << 31); constexpr uint8_t kScrollBarWidth = 10; diff --git a/src/openrct2-ui/interface/Window.cpp b/src/openrct2-ui/interface/Window.cpp index 51a81ae9f6..c22f6ecb4e 100644 --- a/src/openrct2-ui/interface/Window.cpp +++ b/src/openrct2-ui/interface/Window.cpp @@ -32,697 +32,699 @@ #include #include -using namespace OpenRCT2; -using namespace OpenRCT2::Ui; - -// The amount of pixels to scroll per wheel click -constexpr int32_t WindowScrollPixels = 17; - -static int32_t _previousAbsoluteWheel = 0; - -static bool WindowFitsBetweenOthers(const ScreenCoordsXY& loc, int32_t width, int32_t height) +namespace OpenRCT2 { - for (auto& w : g_window_list) + using namespace OpenRCT2::Ui; + + // The amount of pixels to scroll per wheel click + constexpr int32_t WindowScrollPixels = 17; + + static int32_t _previousAbsoluteWheel = 0; + + static bool WindowFitsBetweenOthers(const ScreenCoordsXY& loc, int32_t width, int32_t height) { - if (w->flags & WF_DEAD) - continue; - if (w->flags & WF_STICK_TO_BACK) - continue; - - if (loc.x + width <= w->windowPos.x) - continue; - if (loc.x >= w->windowPos.x + w->width) - continue; - if (loc.y + height <= w->windowPos.y) - continue; - if (loc.y >= w->windowPos.y + w->height) - continue; - return false; - } - - return true; -} - -static bool WindowFitsWithinSpace(const ScreenCoordsXY& loc, int32_t width, int32_t height) -{ - if (loc.x < 0) - return false; - if (loc.y <= kTopToolbarHeight && !(gScreenFlags & SCREEN_FLAGS_TITLE_DEMO)) - return false; - if (loc.x + width > ContextGetWidth()) - return false; - if (loc.y + height > ContextGetHeight()) - return false; - return WindowFitsBetweenOthers(loc, width, height); -} - -static bool WindowFitsOnScreen(const ScreenCoordsXY& loc, int32_t width, int32_t height) -{ - uint16_t screenWidth = ContextGetWidth(); - uint16_t screenHeight = ContextGetHeight(); - int32_t unk; - - unk = -(width / 4); - if (loc.x < unk) - return false; - unk = screenWidth + (unk * 2); - if (loc.x > unk) - return false; - if (loc.y <= kTopToolbarHeight && !(gScreenFlags & SCREEN_FLAGS_TITLE_DEMO)) - return false; - unk = screenHeight - (height / 4); - if (loc.y > unk) - return false; - return WindowFitsBetweenOthers(loc, width, height); -} - -static ScreenCoordsXY ClampWindowToScreen( - const ScreenCoordsXY& pos, const int32_t screenWidth, const int32_t screenHeight, const int32_t width, const int32_t height) -{ - auto screenPos = pos; - if (width > screenWidth || screenPos.x < 0) - screenPos.x = 0; - else if (screenPos.x + width > screenWidth) - screenPos.x = screenWidth - width; - - auto toolbarAllowance = (gScreenFlags & SCREEN_FLAGS_TITLE_DEMO) ? 0 : (kTopToolbarHeight + 1); - if (height - toolbarAllowance > screenHeight || screenPos.y < toolbarAllowance) - screenPos.y = toolbarAllowance; - else if (screenPos.y + height - toolbarAllowance > screenHeight) - screenPos.y = screenHeight + toolbarAllowance - height; - - return screenPos; -} - -static ScreenCoordsXY GetAutoPositionForNewWindow(int32_t width, int32_t height) -{ - auto uiContext = GetContext()->GetUiContext(); - auto screenWidth = uiContext->GetWidth(); - auto screenHeight = uiContext->GetHeight(); - - // Place window in an empty corner of the screen - const ScreenCoordsXY cornerPositions[] = { - { 0, 30 }, // topLeft - { screenWidth - width, 30 }, // topRight - { 0, screenHeight - 34 - height }, // bottomLeft - { screenWidth - width, screenHeight - 34 - height }, // bottomRight - }; - - for (const auto& cornerPos : cornerPositions) - { - if (WindowFitsWithinSpace(cornerPos, width, height)) + for (auto& w : g_window_list) { - return ClampWindowToScreen(cornerPos, screenWidth, screenHeight, width, height); + if (w->flags & WF_DEAD) + continue; + if (w->flags & WF_STICK_TO_BACK) + continue; + + if (loc.x + width <= w->windowPos.x) + continue; + if (loc.x >= w->windowPos.x + w->width) + continue; + if (loc.y + height <= w->windowPos.y) + continue; + if (loc.y >= w->windowPos.y + w->height) + continue; + return false; } + + return true; } - // Place window next to another - for (auto& w : g_window_list) + static bool WindowFitsWithinSpace(const ScreenCoordsXY& loc, int32_t width, int32_t height) { - if (w->flags & WF_DEAD) - continue; - if (w->flags & WF_STICK_TO_BACK) - continue; + if (loc.x < 0) + return false; + if (loc.y <= kTopToolbarHeight && !(gScreenFlags & SCREEN_FLAGS_TITLE_DEMO)) + return false; + if (loc.x + width > ContextGetWidth()) + return false; + if (loc.y + height > ContextGetHeight()) + return false; + return WindowFitsBetweenOthers(loc, width, height); + } - const ScreenCoordsXY offsets[] = { - { w->width + 2, 0 }, - { -w->width - 2, 0 }, - { 0, w->height + 2 }, - { 0, -w->height - 2 }, - { w->width + 2, -w->height - 2 }, - { -w->width - 2, -w->height - 2 }, - { w->width + 2, w->height + 2 }, - { -w->width - 2, w->height + 2 }, + static bool WindowFitsOnScreen(const ScreenCoordsXY& loc, int32_t width, int32_t height) + { + uint16_t screenWidth = ContextGetWidth(); + uint16_t screenHeight = ContextGetHeight(); + int32_t unk; + + unk = -(width / 4); + if (loc.x < unk) + return false; + unk = screenWidth + (unk * 2); + if (loc.x > unk) + return false; + if (loc.y <= kTopToolbarHeight && !(gScreenFlags & SCREEN_FLAGS_TITLE_DEMO)) + return false; + unk = screenHeight - (height / 4); + if (loc.y > unk) + return false; + return WindowFitsBetweenOthers(loc, width, height); + } + + static ScreenCoordsXY ClampWindowToScreen( + const ScreenCoordsXY& pos, const int32_t screenWidth, const int32_t screenHeight, const int32_t width, + const int32_t height) + { + auto screenPos = pos; + if (width > screenWidth || screenPos.x < 0) + screenPos.x = 0; + else if (screenPos.x + width > screenWidth) + screenPos.x = screenWidth - width; + + auto toolbarAllowance = (gScreenFlags & SCREEN_FLAGS_TITLE_DEMO) ? 0 : (kTopToolbarHeight + 1); + if (height - toolbarAllowance > screenHeight || screenPos.y < toolbarAllowance) + screenPos.y = toolbarAllowance; + else if (screenPos.y + height - toolbarAllowance > screenHeight) + screenPos.y = screenHeight + toolbarAllowance - height; + + return screenPos; + } + + static ScreenCoordsXY GetAutoPositionForNewWindow(int32_t width, int32_t height) + { + auto uiContext = GetContext()->GetUiContext(); + auto screenWidth = uiContext->GetWidth(); + auto screenHeight = uiContext->GetHeight(); + + // Place window in an empty corner of the screen + const ScreenCoordsXY cornerPositions[] = { + { 0, 30 }, // topLeft + { screenWidth - width, 30 }, // topRight + { 0, screenHeight - 34 - height }, // bottomLeft + { screenWidth - width, screenHeight - 34 - height }, // bottomRight }; - for (const auto& offset : offsets) + for (const auto& cornerPos : cornerPositions) { - auto screenPos = w->windowPos + offset; - if (WindowFitsWithinSpace(screenPos, width, height)) + if (WindowFitsWithinSpace(cornerPos, width, height)) { - return ClampWindowToScreen(screenPos, screenWidth, screenHeight, width, height); + return ClampWindowToScreen(cornerPos, screenWidth, screenHeight, width, height); } } - } - // Overlap - for (auto& w : g_window_list) - { - if (w->flags & WF_DEAD) - continue; - if (w->flags & WF_STICK_TO_BACK) - continue; - - const ScreenCoordsXY offsets[] = { - { w->width + 2, 0 }, - { -w->width - 2, 0 }, - { 0, w->height + 2 }, - { 0, -w->height - 2 }, - }; - - for (const auto& offset : offsets) + // Place window next to another + for (auto& w : g_window_list) { - auto screenPos = w->windowPos + offset; - if (WindowFitsOnScreen(screenPos, width, height)) + if (w->flags & WF_DEAD) + continue; + if (w->flags & WF_STICK_TO_BACK) + continue; + + const ScreenCoordsXY offsets[] = { + { w->width + 2, 0 }, + { -w->width - 2, 0 }, + { 0, w->height + 2 }, + { 0, -w->height - 2 }, + { w->width + 2, -w->height - 2 }, + { -w->width - 2, -w->height - 2 }, + { w->width + 2, w->height + 2 }, + { -w->width - 2, w->height + 2 }, + }; + + for (const auto& offset : offsets) { - return ClampWindowToScreen(screenPos, screenWidth, screenHeight, width, height); + auto screenPos = w->windowPos + offset; + if (WindowFitsWithinSpace(screenPos, width, height)) + { + return ClampWindowToScreen(screenPos, screenWidth, screenHeight, width, height); + } } } - } - // Cascade - auto screenPos = ScreenCoordsXY{ 0, 30 }; - for (auto& w : g_window_list) - { - if (screenPos == w->windowPos) + // Overlap + for (auto& w : g_window_list) { - screenPos.x += 5; - screenPos.y += 5; + if (w->flags & WF_DEAD) + continue; + if (w->flags & WF_STICK_TO_BACK) + continue; + + const ScreenCoordsXY offsets[] = { + { w->width + 2, 0 }, + { -w->width - 2, 0 }, + { 0, w->height + 2 }, + { 0, -w->height - 2 }, + }; + + for (const auto& offset : offsets) + { + auto screenPos = w->windowPos + offset; + if (WindowFitsOnScreen(screenPos, width, height)) + { + return ClampWindowToScreen(screenPos, screenWidth, screenHeight, width, height); + } + } } + + // Cascade + auto screenPos = ScreenCoordsXY{ 0, 30 }; + for (auto& w : g_window_list) + { + if (screenPos == w->windowPos) + { + screenPos.x += 5; + screenPos.y += 5; + } + } + + return ClampWindowToScreen(screenPos, screenWidth, screenHeight, width, height); } - return ClampWindowToScreen(screenPos, screenWidth, screenHeight, width, height); -} - -static ScreenCoordsXY GetCentrePositionForNewWindow(int32_t width, int32_t height) -{ - auto uiContext = GetContext()->GetUiContext(); - auto screenWidth = uiContext->GetWidth(); - auto screenHeight = uiContext->GetHeight(); - return ScreenCoordsXY{ (screenWidth - width) / 2, std::max(kTopToolbarHeight + 1, (screenHeight - height) / 2) }; -} - -static int32_t WindowGetWidgetIndex(const WindowBase& w, Widget* widget) -{ - int32_t i = 0; - for (Widget* widget2 = w.widgets; widget2->type != WindowWidgetType::Last; widget2++, i++) - if (widget == widget2) - return i; - return -1; -} - -static int32_t WindowGetScrollIndex(const WindowBase& w, int32_t targetWidgetIndex) -{ - if (w.widgets[targetWidgetIndex].type != WindowWidgetType::Scroll) - return -1; - - int32_t scrollIndex = 0; - WidgetIndex widgetIndex = 0; - for (Widget* widget = w.widgets; widget->type != WindowWidgetType::Last; widget++, widgetIndex++) + static ScreenCoordsXY GetCentrePositionForNewWindow(int32_t width, int32_t height) { - if (widgetIndex == targetWidgetIndex) - break; - if (widget->type == WindowWidgetType::Scroll) - scrollIndex++; + auto uiContext = GetContext()->GetUiContext(); + auto screenWidth = uiContext->GetWidth(); + auto screenHeight = uiContext->GetHeight(); + return ScreenCoordsXY{ (screenWidth - width) / 2, std::max(kTopToolbarHeight + 1, (screenHeight - height) / 2) }; } - return scrollIndex; -} - -static Widget* WindowGetScrollWidget(const WindowBase& w, int32_t scrollIndex) -{ - for (Widget* widget = w.widgets; widget->type != WindowWidgetType::Last; widget++) + static int32_t WindowGetWidgetIndex(const WindowBase& w, Widget* widget) { - if (widget->type != WindowWidgetType::Scroll) - continue; - - if (scrollIndex == 0) - return widget; - scrollIndex--; + const auto it = std::find_if( + w.widgets.begin(), w.widgets.end(), [&](auto& otherWidget) { return &otherWidget == widget; }); + if (it == w.widgets.end()) + return -1; + return std::distance(w.widgets.begin(), it); } - return nullptr; -} - -/** - * - * rct2: 0x006E78E3 - */ -static void WindowScrollWheelInput(WindowBase& w, int32_t scrollIndex, int32_t wheel) -{ - auto& scroll = w.scrolls[scrollIndex]; - Widget* widget = WindowGetScrollWidget(w, scrollIndex); - WidgetIndex widgetIndex = WindowGetWidgetIndex(w, widget); - - if (scroll.flags & VSCROLLBAR_VISIBLE) + static int32_t WindowGetScrollIndex(const WindowBase& w, int32_t targetWidgetIndex) { - int32_t size = widget->height() - 1; - if (scroll.flags & HSCROLLBAR_VISIBLE) - size -= 11; - size = std::max(0, scroll.contentHeight - size); - scroll.contentOffsetY = std::min(std::max(0, scroll.contentOffsetY + wheel), size); + if (w.widgets[targetWidgetIndex].type != WindowWidgetType::Scroll) + return -1; + + int32_t scrollIndex = 0; + for (WidgetIndex widgetIndex = 0; widgetIndex < w.widgets.size(); widgetIndex++) + { + if (widgetIndex == targetWidgetIndex) + break; + auto& widget = w.widgets[widgetIndex]; + if (widget.type == WindowWidgetType::Scroll) + scrollIndex++; + } + + return scrollIndex; } - else + + static Widget* WindowGetScrollWidget(const WindowBase& w, int32_t scrollIndex) { - int32_t size = widget->width() - 1; + for (WidgetIndex widgetIndex = 0; widgetIndex < w.widgets.size(); widgetIndex++) + { + auto& widget = w.widgets[widgetIndex]; + if (widget.type != WindowWidgetType::Scroll) + continue; + + if (scrollIndex == 0) + return const_cast(&widget); + scrollIndex--; + } + + return nullptr; + } + + /** + * + * rct2: 0x006E78E3 + */ + static void WindowScrollWheelInput(WindowBase& w, int32_t scrollIndex, int32_t wheel) + { + auto& scroll = w.scrolls[scrollIndex]; + Widget* widget = WindowGetScrollWidget(w, scrollIndex); + WidgetIndex widgetIndex = WindowGetWidgetIndex(w, widget); + if (scroll.flags & VSCROLLBAR_VISIBLE) - size -= 11; - size = std::max(0, scroll.contentWidth - size); - scroll.contentOffsetX = std::min(std::max(0, scroll.contentOffsetX + wheel), size); - } - - WidgetScrollUpdateThumbs(w, widgetIndex); - WidgetInvalidate(w, widgetIndex); -} - -/** - * - * rct2: 0x006E793B - */ -static int32_t WindowWheelInput(WindowBase& w, int32_t wheel) -{ - int32_t i = 0; - for (Widget* widget = w.widgets; widget->type != WindowWidgetType::Last; widget++) - { - if (widget->type != WindowWidgetType::Scroll) - continue; - - // Originally always checked first scroll view, bug maybe? - const auto& scroll = w.scrolls[i]; - if (scroll.flags & (HSCROLLBAR_VISIBLE | VSCROLLBAR_VISIBLE)) { - WindowScrollWheelInput(w, i, wheel); - return 1; - } - i++; - } - - return 0; -} - -/** - * - * rct2: 0x006E79FB - */ -static void WindowViewportWheelInput(WindowBase& w, int32_t wheel) -{ - if (gScreenFlags & (SCREEN_FLAGS_TRACK_MANAGER | SCREEN_FLAGS_TITLE_DEMO)) - return; - - if (wheel < 0) - Windows::WindowZoomIn(w, true); - else if (wheel > 0) - Windows::WindowZoomOut(w, true); -} - -static bool isSpinnerGroup(WindowBase& w, WidgetIndex index, WindowWidgetType buttonType) -{ - const auto& widgets = w.widgets; - - if (widgets[index].type != WindowWidgetType::Spinner && widgets[index].type != WindowWidgetType::ImgBtn) - return false; - - if (widgets[index + 1].type != buttonType) - return false; - - if (widgets[index + 2].type != buttonType) - return false; - - return true; -} - -static std::optional getSpinnerGroupWidgetIndex(WindowBase& w, WidgetIndex startIndex) -{ - // We only iterate 3 times as we might be at the spinner or one of its buttons. - for (WidgetIndex index = 0; index < 3; index++) - { - const auto reverseIndex = startIndex - index; - if (reverseIndex < 0) - { - break; - } - - if (isSpinnerGroup(w, reverseIndex, WindowWidgetType::TrnBtn)) - { - return reverseIndex; - } - - if (isSpinnerGroup(w, reverseIndex, WindowWidgetType::Button)) - { - return reverseIndex; - } - } - - return std::nullopt; -} - -// Allow mouse wheel scrolling to manipulate spinner widgets and tool sizes -static bool WindowOtherWheelInput(WindowBase& w, WidgetIndex widgetIndex, int32_t wheel) -{ - // HACK: Until we have a new window system that allows us to add new events like mouse wheel easily, - // this selective approach will have to do. - - const auto spinnerGroupIndex = getSpinnerGroupWidgetIndex(w, widgetIndex); - if (!spinnerGroupIndex.has_value()) - { - return false; - } - - const auto entryWidgetType = w.widgets[*spinnerGroupIndex].type; - auto targetWidgetIndex = *spinnerGroupIndex; - - if (entryWidgetType == WindowWidgetType::ImgBtn) - { - auto expectedContent1 = ImageId(SPR_LAND_TOOL_DECREASE, FilterPaletteID::PaletteNull); - auto expectedContent2 = ImageId(SPR_LAND_TOOL_INCREASE, FilterPaletteID::PaletteNull); - - auto button1Image = w.widgets[*spinnerGroupIndex + 1].image; - auto button2Image = w.widgets[*spinnerGroupIndex + 2].image; - if (button1Image != expectedContent1 || button2Image != expectedContent2) - { - return false; - } - - // Expected widget order: decrease, increase - targetWidgetIndex += wheel < 0 ? 2 : 1; - } - else if (entryWidgetType == WindowWidgetType::Spinner) - { - auto button1StringId = w.widgets[*spinnerGroupIndex + 1].text; - auto button2StringId = w.widgets[*spinnerGroupIndex + 2].text; - if (button1StringId != STR_NUMERIC_UP || button2StringId != STR_NUMERIC_DOWN) - { - return false; - } - - // Expected widget order: increase, decrease - targetWidgetIndex += wheel < 0 ? 1 : 2; - } - - if (WidgetIsDisabled(w, targetWidgetIndex)) - { - return false; - } - - w.OnMouseDown(targetWidgetIndex); - return true; -} - -/** - * - * rct2: 0x006E7868 - */ -void WindowAllWheelInput() -{ - // Get wheel value - auto cursorState = ContextGetCursorState(); - int32_t absolute_wheel = cursorState->wheel; - int32_t relative_wheel = absolute_wheel - _previousAbsoluteWheel; - int32_t pixel_scroll = relative_wheel * WindowScrollPixels; - _previousAbsoluteWheel = absolute_wheel; - - if (relative_wheel == 0) - return; - - // Check window cursor is over - if (!(InputTestFlag(INPUT_FLAG_5))) - { - auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); - WindowBase* w = windowMgr->FindFromPoint(cursorState->position); - if (w != nullptr) - { - // Check if main window - if (w->classification == WindowClass::MainWindow || w->classification == WindowClass::Viewport) - { - WindowViewportWheelInput(*w, relative_wheel); - return; - } - - // Check scroll view, cursor is over - WidgetIndex widgetIndex = windowMgr->FindWidgetFromPoint(*w, cursorState->position); - if (widgetIndex != -1) - { - const auto& widget = w->widgets[widgetIndex]; - if (widget.type == WindowWidgetType::Scroll) - { - int32_t scrollIndex = WindowGetScrollIndex(*w, widgetIndex); - const auto& scroll = w->scrolls[scrollIndex]; - if (scroll.flags & (HSCROLLBAR_VISIBLE | VSCROLLBAR_VISIBLE)) - { - WindowScrollWheelInput(*w, WindowGetScrollIndex(*w, widgetIndex), pixel_scroll); - return; - } - } - else - { - if (WindowOtherWheelInput(*w, widgetIndex, pixel_scroll)) - { - return; - } - } - - // Check other scroll views on window - if (WindowWheelInput(*w, pixel_scroll)) - return; - } - } - } -} - -void ApplyScreenSaverLockSetting() -{ - Config::Get().general.DisableScreensaver ? SDL_DisableScreenSaver() : SDL_EnableScreenSaver(); -} - -/** - * - * rct2: 0x006EA776 - */ -static void WindowInvalidatePressedImageButton(const WindowBase& w) -{ - WidgetIndex widgetIndex; - Widget* widget; - - widgetIndex = 0; - for (widget = w.widgets; widget->type != WindowWidgetType::Last; widget++, widgetIndex++) - { - if (widget->type != WindowWidgetType::ImgBtn) - continue; - - if (WidgetIsPressed(w, widgetIndex) || isToolActive(w, widgetIndex)) - GfxSetDirtyBlocks({ w.windowPos, w.windowPos + ScreenCoordsXY{ w.width, w.height } }); - } -} - -void Window::ScrollToViewport() -{ - if (viewport == nullptr || !focus.has_value()) - return; - - CoordsXYZ newCoords = focus.value().GetPos(); - - auto mainWindow = WindowGetMain(); - if (mainWindow != nullptr) - WindowScrollToLocation(*mainWindow, newCoords); -} - -void Window::OnDraw(DrawPixelInfo& dpi) -{ - Windows::WindowDrawWidgets(*this, dpi); -} - -void Window::OnDrawWidget(WidgetIndex widgetIndex, DrawPixelInfo& dpi) -{ - WidgetDraw(dpi, *this, widgetIndex); -} - -void Window::InitScrollWidgets() -{ - Windows::WindowInitScrollWidgets(*this); -} - -void Window::InvalidateWidget(WidgetIndex widgetIndex) -{ - WidgetInvalidate(*this, widgetIndex); -} - -bool Window::IsWidgetDisabled(WidgetIndex widgetIndex) const -{ - return WidgetIsDisabled(*this, widgetIndex); -} - -bool Window::IsWidgetPressed(WidgetIndex widgetIndex) const -{ - return WidgetIsPressed(*this, widgetIndex); -} - -void Window::SetWidgetEnabled(WidgetIndex widgetIndex, bool value) -{ - WidgetSetEnabled(*this, widgetIndex, value); -} - -void Window::SetWidgetDisabled(WidgetIndex widgetIndex, bool value) -{ - WidgetSetDisabled(*this, widgetIndex, value); -} - -void Window::SetWidgetDisabledAndInvalidate(WidgetIndex widgetIndex, bool value) -{ - bool oldState = IsWidgetDisabled(widgetIndex); - if (oldState != value) - { - WidgetSetDisabled(*this, widgetIndex, value); - InvalidateWidget(widgetIndex); - } -} - -void Window::SetWidgetPressed(WidgetIndex widgetIndex, bool value) -{ - WidgetSetPressed(*this, widgetIndex, value); -} - -void Window::SetCheckboxValue(WidgetIndex widgetIndex, bool value) -{ - SetWidgetPressed(widgetIndex, value); -} - -void Window::DrawWidgets(DrawPixelInfo& dpi) -{ - Windows::WindowDrawWidgets(*this, dpi); -} - -void Window::Close() -{ - CloseWindowModifier modifier = GetCloseModifier(); - - if (modifier == CloseWindowModifier::Shift) - { - CloseOthers(); - } - else if (modifier == CloseWindowModifier::Control) - { - CloseOthersOfThisClass(); - } - else - { - WindowClose(*this); - } -} - -void Window::CloseOthers() -{ - WindowCloseAllExceptNumberAndClass(number, classification); -} - -void Window::CloseOthersOfThisClass() -{ - WindowCloseByClass(classification); -} - -CloseWindowModifier Window::GetCloseModifier() -{ - CloseWindowModifier lastModifier = CloseWindowModifier::None; - - if (gLastCloseModifier.window.number == number && gLastCloseModifier.window.classification == classification) - { - lastModifier = gLastCloseModifier.modifier; - } - - gLastCloseModifier.modifier = CloseWindowModifier::None; - - return lastModifier; -} - -void Window::TextInputOpen( - WidgetIndex callWidget, StringId title, StringId description, const Formatter& descriptionArgs, StringId existingText, - uintptr_t existingArgs, int32_t maxLength) -{ - OpenRCT2::Ui::Windows::WindowTextInputOpen( - this, callWidget, title, description, descriptionArgs, existingText, existingArgs, maxLength); -} - -void Window::ResizeFrame() -{ - // Frame - widgets[0].right = width - 1; - widgets[0].bottom = height - 1; - // Title - widgets[1].right = width - 2; - // Close button - if (Config::Get().interface.WindowButtonsOnTheLeft) - { - widgets[2].left = 2; - widgets[2].right = 2 + kCloseButtonWidth; - } - else - { - widgets[2].left = width - 3 - kCloseButtonWidth; - widgets[2].right = width - 3; - } -} - -void Window::ResizeFrameWithPage() -{ - ResizeFrame(); - // Page background - widgets[3].right = width - 1; - widgets[3].bottom = height - 1; -} - -void Window::ResizeSpinner(WidgetIndex widgetIndex, const ScreenCoordsXY& origin, const ScreenSize& size) -{ - auto right = origin.x + size.width - 1; - auto bottom = origin.y + size.height - 1; - widgets[widgetIndex].left = origin.x; - widgets[widgetIndex].top = origin.y; - widgets[widgetIndex].right = right; - widgets[widgetIndex].bottom = bottom; - - widgets[widgetIndex + 1].left = right - size.height; // subtract height to maintain aspect ratio - widgets[widgetIndex + 1].top = origin.y + 1; - widgets[widgetIndex + 1].right = right - 1; - widgets[widgetIndex + 1].bottom = bottom - 1; - - widgets[widgetIndex + 2].left = right - size.height * 2; - widgets[widgetIndex + 2].top = origin.y + 1; - widgets[widgetIndex + 2].right = right - size.height - 1; - widgets[widgetIndex + 2].bottom = bottom - 1; -} - -void Window::ResizeDropdown(WidgetIndex widgetIndex, const ScreenCoordsXY& origin, const ScreenSize& size) -{ - auto right = origin.x + size.width - 1; - auto bottom = origin.y + size.height - 1; - widgets[widgetIndex].left = origin.x; - widgets[widgetIndex].top = origin.y; - widgets[widgetIndex].right = right; - widgets[widgetIndex].bottom = bottom; - - widgets[widgetIndex + 1].left = right - size.height + 1; // subtract height to maintain aspect ratio - widgets[widgetIndex + 1].top = origin.y + 1; - widgets[widgetIndex + 1].right = right - 1; - widgets[widgetIndex + 1].bottom = bottom - 1; -} - -void WindowAlignTabs(WindowBase* w, WidgetIndex start_tab_id, WidgetIndex end_tab_id) -{ - int32_t i, x = w->widgets[start_tab_id].left; - int32_t tab_width = w->widgets[start_tab_id].width(); - - for (i = start_tab_id; i <= end_tab_id; i++) - { - auto& widget = w->widgets[i]; - if (!WidgetIsDisabled(*w, i)) - { - widget.left = x; - widget.right = x + tab_width; - x += tab_width + 1; + int32_t size = widget->height() - 1; + if (scroll.flags & HSCROLLBAR_VISIBLE) + size -= 11; + size = std::max(0, scroll.contentHeight - size); + scroll.contentOffsetY = std::min(std::max(0, scroll.contentOffsetY + wheel), size); } else { - // Workaround #20535: Avoid disabled widgets from sharing the same space as active ones, otherwise - // WindowFindWidgetFromPoint could return the disabled one, causing issues. - widget.left = 0; - widget.right = 0; + int32_t size = widget->width() - 1; + if (scroll.flags & VSCROLLBAR_VISIBLE) + size -= 11; + size = std::max(0, scroll.contentWidth - size); + scroll.contentOffsetX = std::min(std::max(0, scroll.contentOffsetX + wheel), size); + } + + WidgetScrollUpdateThumbs(w, widgetIndex); + WidgetInvalidate(w, widgetIndex); + } + + /** + * + * rct2: 0x006E793B + */ + static int32_t WindowWheelInput(WindowBase& w, int32_t wheel) + { + int32_t scrollIndex = 0; + for (WidgetIndex widgetIndex = 0; widgetIndex < w.widgets.size(); widgetIndex++) + { + const auto& widget = w.widgets[widgetIndex]; + if (widget.type != WindowWidgetType::Scroll) + continue; + + // Originally always checked first scroll view, bug maybe? + const auto& scroll = w.scrolls[scrollIndex]; + if (scroll.flags & (HSCROLLBAR_VISIBLE | VSCROLLBAR_VISIBLE)) + { + WindowScrollWheelInput(w, scrollIndex, wheel); + return 1; + } + scrollIndex++; + } + + return 0; + } + + /** + * + * rct2: 0x006E79FB + */ + static void WindowViewportWheelInput(WindowBase& w, int32_t wheel) + { + if (gScreenFlags & (SCREEN_FLAGS_TRACK_MANAGER | SCREEN_FLAGS_TITLE_DEMO)) + return; + + if (wheel < 0) + Windows::WindowZoomIn(w, true); + else if (wheel > 0) + Windows::WindowZoomOut(w, true); + } + + static bool isSpinnerGroup(WindowBase& w, WidgetIndex index, WindowWidgetType buttonType) + { + const auto& widgets = w.widgets; + + if (widgets[index].type != WindowWidgetType::Spinner && widgets[index].type != WindowWidgetType::ImgBtn) + return false; + + if (widgets[index + 1].type != buttonType) + return false; + + if (widgets[index + 2].type != buttonType) + return false; + + return true; + } + + static std::optional getSpinnerGroupWidgetIndex(WindowBase& w, WidgetIndex startIndex) + { + // We only iterate 3 times as we might be at the spinner or one of its buttons. + for (WidgetIndex index = 0; index < 3; index++) + { + const auto reverseIndex = startIndex - index; + if (reverseIndex < 0) + { + break; + } + + if (isSpinnerGroup(w, reverseIndex, WindowWidgetType::TrnBtn)) + { + return reverseIndex; + } + + if (isSpinnerGroup(w, reverseIndex, WindowWidgetType::Button)) + { + return reverseIndex; + } + } + + return std::nullopt; + } + + // Allow mouse wheel scrolling to manipulate spinner widgets and tool sizes + static bool WindowOtherWheelInput(WindowBase& w, WidgetIndex widgetIndex, int32_t wheel) + { + // HACK: Until we have a new window system that allows us to add new events like mouse wheel easily, + // this selective approach will have to do. + + const auto spinnerGroupIndex = getSpinnerGroupWidgetIndex(w, widgetIndex); + if (!spinnerGroupIndex.has_value()) + { + return false; + } + + const auto entryWidgetType = w.widgets[*spinnerGroupIndex].type; + auto targetWidgetIndex = *spinnerGroupIndex; + + if (entryWidgetType == WindowWidgetType::ImgBtn) + { + auto expectedContent1 = ImageId(SPR_LAND_TOOL_DECREASE, FilterPaletteID::PaletteNull); + auto expectedContent2 = ImageId(SPR_LAND_TOOL_INCREASE, FilterPaletteID::PaletteNull); + + auto button1Image = w.widgets[*spinnerGroupIndex + 1].image; + auto button2Image = w.widgets[*spinnerGroupIndex + 2].image; + if (button1Image != expectedContent1 || button2Image != expectedContent2) + { + return false; + } + + // Expected widget order: decrease, increase + targetWidgetIndex += wheel < 0 ? 2 : 1; + } + else if (entryWidgetType == WindowWidgetType::Spinner) + { + auto button1StringId = w.widgets[*spinnerGroupIndex + 1].text; + auto button2StringId = w.widgets[*spinnerGroupIndex + 2].text; + if (button1StringId != STR_NUMERIC_UP || button2StringId != STR_NUMERIC_DOWN) + { + return false; + } + + // Expected widget order: increase, decrease + targetWidgetIndex += wheel < 0 ? 1 : 2; + } + + if (WidgetIsDisabled(w, targetWidgetIndex)) + { + return false; + } + + w.OnMouseDown(targetWidgetIndex); + return true; + } + + /** + * + * rct2: 0x006E7868 + */ + void WindowAllWheelInput() + { + // Get wheel value + auto cursorState = ContextGetCursorState(); + int32_t absolute_wheel = cursorState->wheel; + int32_t relative_wheel = absolute_wheel - _previousAbsoluteWheel; + int32_t pixel_scroll = relative_wheel * WindowScrollPixels; + _previousAbsoluteWheel = absolute_wheel; + + if (relative_wheel == 0) + return; + + // Check window cursor is over + if (!(InputTestFlag(INPUT_FLAG_5))) + { + auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); + WindowBase* w = windowMgr->FindFromPoint(cursorState->position); + if (w != nullptr) + { + // Check if main window + if (w->classification == WindowClass::MainWindow || w->classification == WindowClass::Viewport) + { + WindowViewportWheelInput(*w, relative_wheel); + return; + } + + // Check scroll view, cursor is over + WidgetIndex widgetIndex = windowMgr->FindWidgetFromPoint(*w, cursorState->position); + if (widgetIndex != kWidgetIndexNull) + { + const auto& widget = w->widgets[widgetIndex]; + if (widget.type == WindowWidgetType::Scroll) + { + int32_t scrollIndex = WindowGetScrollIndex(*w, widgetIndex); + const auto& scroll = w->scrolls[scrollIndex]; + if (scroll.flags & (HSCROLLBAR_VISIBLE | VSCROLLBAR_VISIBLE)) + { + WindowScrollWheelInput(*w, WindowGetScrollIndex(*w, widgetIndex), pixel_scroll); + return; + } + } + else + { + if (WindowOtherWheelInput(*w, widgetIndex, pixel_scroll)) + { + return; + } + } + + // Check other scroll views on window + if (WindowWheelInput(*w, pixel_scroll)) + return; + } + } } } -} -ScreenCoordsXY WindowGetViewportSoundIconPos(WindowBase& w) -{ - const uint8_t buttonOffset = (Config::Get().interface.WindowButtonsOnTheLeft) ? kCloseButtonWidth + 2 : 0; - return w.windowPos + ScreenCoordsXY{ 2 + buttonOffset, 2 }; -} + void ApplyScreenSaverLockSetting() + { + Config::Get().general.DisableScreensaver ? SDL_DisableScreenSaver() : SDL_EnableScreenSaver(); + } + + /** + * + * rct2: 0x006EA776 + */ + static void WindowInvalidatePressedImageButton(const WindowBase& w) + { + for (WidgetIndex widgetIndex = 0; widgetIndex < w.widgets.size(); widgetIndex++) + { + auto& widget = w.widgets[widgetIndex]; + if (widget.type != WindowWidgetType::ImgBtn) + continue; + + if (WidgetIsPressed(w, widgetIndex) || isToolActive(w, widgetIndex)) + GfxSetDirtyBlocks({ w.windowPos, w.windowPos + ScreenCoordsXY{ w.width, w.height } }); + } + } + + void Window::ScrollToViewport() + { + if (viewport == nullptr || !focus.has_value()) + return; + + CoordsXYZ newCoords = focus.value().GetPos(); + + auto mainWindow = WindowGetMain(); + if (mainWindow != nullptr) + WindowScrollToLocation(*mainWindow, newCoords); + } + + void Window::OnDraw(DrawPixelInfo& dpi) + { + Windows::WindowDrawWidgets(*this, dpi); + } + + void Window::OnDrawWidget(WidgetIndex widgetIndex, DrawPixelInfo& dpi) + { + WidgetDraw(dpi, *this, widgetIndex); + } + + void Window::InitScrollWidgets() + { + Windows::WindowInitScrollWidgets(*this); + } + + void Window::InvalidateWidget(WidgetIndex widgetIndex) + { + WidgetInvalidate(*this, widgetIndex); + } + + bool Window::IsWidgetDisabled(WidgetIndex widgetIndex) const + { + return WidgetIsDisabled(*this, widgetIndex); + } + + bool Window::IsWidgetPressed(WidgetIndex widgetIndex) const + { + return WidgetIsPressed(*this, widgetIndex); + } + + void Window::SetWidgetEnabled(WidgetIndex widgetIndex, bool value) + { + WidgetSetEnabled(*this, widgetIndex, value); + } + + void Window::SetWidgetDisabled(WidgetIndex widgetIndex, bool value) + { + WidgetSetDisabled(*this, widgetIndex, value); + } + + void Window::SetWidgetDisabledAndInvalidate(WidgetIndex widgetIndex, bool value) + { + bool oldState = IsWidgetDisabled(widgetIndex); + if (oldState != value) + { + WidgetSetDisabled(*this, widgetIndex, value); + InvalidateWidget(widgetIndex); + } + } + + void Window::SetWidgetPressed(WidgetIndex widgetIndex, bool value) + { + WidgetSetPressed(*this, widgetIndex, value); + } + + void Window::SetCheckboxValue(WidgetIndex widgetIndex, bool value) + { + SetWidgetPressed(widgetIndex, value); + } + + void Window::DrawWidgets(DrawPixelInfo& dpi) + { + Windows::WindowDrawWidgets(*this, dpi); + } + + void Window::Close() + { + CloseWindowModifier modifier = GetCloseModifier(); + + if (modifier == CloseWindowModifier::Shift) + { + CloseOthers(); + } + else if (modifier == CloseWindowModifier::Control) + { + CloseOthersOfThisClass(); + } + else + { + WindowClose(*this); + } + } + + void Window::CloseOthers() + { + WindowCloseAllExceptNumberAndClass(number, classification); + } + + void Window::CloseOthersOfThisClass() + { + WindowCloseByClass(classification); + } + + CloseWindowModifier Window::GetCloseModifier() + { + CloseWindowModifier lastModifier = CloseWindowModifier::None; + + if (gLastCloseModifier.window.number == number && gLastCloseModifier.window.classification == classification) + { + lastModifier = gLastCloseModifier.modifier; + } + + gLastCloseModifier.modifier = CloseWindowModifier::None; + + return lastModifier; + } + + void Window::TextInputOpen( + WidgetIndex callWidget, StringId title, StringId description, const Formatter& descriptionArgs, StringId existingText, + uintptr_t existingArgs, int32_t maxLength) + { + OpenRCT2::Ui::Windows::WindowTextInputOpen( + this, callWidget, title, description, descriptionArgs, existingText, existingArgs, maxLength); + } + + void Window::ResizeFrame() + { + // Frame + widgets[0].right = width - 1; + widgets[0].bottom = height - 1; + // Title + widgets[1].right = width - 2; + // Close button + if (Config::Get().interface.WindowButtonsOnTheLeft) + { + widgets[2].left = 2; + widgets[2].right = 2 + kCloseButtonWidth; + } + else + { + widgets[2].left = width - 3 - kCloseButtonWidth; + widgets[2].right = width - 3; + } + } + + void Window::ResizeFrameWithPage() + { + ResizeFrame(); + // Page background + widgets[3].right = width - 1; + widgets[3].bottom = height - 1; + } + + void Window::ResizeSpinner(WidgetIndex widgetIndex, const ScreenCoordsXY& origin, const ScreenSize& size) + { + auto right = origin.x + size.width - 1; + auto bottom = origin.y + size.height - 1; + widgets[widgetIndex].left = origin.x; + widgets[widgetIndex].top = origin.y; + widgets[widgetIndex].right = right; + widgets[widgetIndex].bottom = bottom; + + widgets[widgetIndex + 1].left = right - size.height; // subtract height to maintain aspect ratio + widgets[widgetIndex + 1].top = origin.y + 1; + widgets[widgetIndex + 1].right = right - 1; + widgets[widgetIndex + 1].bottom = bottom - 1; + + widgets[widgetIndex + 2].left = right - size.height * 2; + widgets[widgetIndex + 2].top = origin.y + 1; + widgets[widgetIndex + 2].right = right - size.height - 1; + widgets[widgetIndex + 2].bottom = bottom - 1; + } + + void Window::ResizeDropdown(WidgetIndex widgetIndex, const ScreenCoordsXY& origin, const ScreenSize& size) + { + auto right = origin.x + size.width - 1; + auto bottom = origin.y + size.height - 1; + widgets[widgetIndex].left = origin.x; + widgets[widgetIndex].top = origin.y; + widgets[widgetIndex].right = right; + widgets[widgetIndex].bottom = bottom; + + widgets[widgetIndex + 1].left = right - size.height + 1; // subtract height to maintain aspect ratio + widgets[widgetIndex + 1].top = origin.y + 1; + widgets[widgetIndex + 1].right = right - 1; + widgets[widgetIndex + 1].bottom = bottom - 1; + } + + void WindowAlignTabs(WindowBase* w, WidgetIndex start_tab_id, WidgetIndex end_tab_id) + { + int32_t i, x = w->widgets[start_tab_id].left; + int32_t tab_width = w->widgets[start_tab_id].width(); + + for (i = start_tab_id; i <= end_tab_id; i++) + { + auto& widget = w->widgets[i]; + if (!WidgetIsDisabled(*w, i)) + { + widget.left = x; + widget.right = x + tab_width; + x += tab_width + 1; + } + else + { + // Workaround #20535: Avoid disabled widgets from sharing the same space as active ones, otherwise + // WindowFindWidgetFromPoint could return the disabled one, causing issues. + widget.left = 0; + widget.right = 0; + } + } + } + + ScreenCoordsXY WindowGetViewportSoundIconPos(WindowBase& w) + { + const uint8_t buttonOffset = (Config::Get().interface.WindowButtonsOnTheLeft) ? kCloseButtonWidth + 2 : 0; + return w.windowPos + ScreenCoordsXY{ 2 + buttonOffset, 2 }; + } +} // namespace OpenRCT2 namespace OpenRCT2::Ui::Windows { @@ -879,7 +881,7 @@ namespace OpenRCT2::Ui::Windows { WidgetInvalidate(*w, _currentTextBox.widget_index); } - _currentTextBox.widget_index = static_cast(WindowWidgetType::Last); + _currentTextBox.widget_index = kWidgetIndexNull; } } @@ -958,14 +960,11 @@ namespace OpenRCT2::Ui::Windows void WindowUpdateScrollWidgets(WindowBase& w) { int32_t scrollIndex, width, height, scrollPositionChanged; - WidgetIndex widgetIndex; - Widget* widget; - - widgetIndex = 0; scrollIndex = 0; - for (widget = w.widgets; widget->type != WindowWidgetType::Last; widget++, widgetIndex++) + for (WidgetIndex widgetIndex = 0; widgetIndex < w.widgets.size(); widgetIndex++) { - if (widget->type != WindowWidgetType::Scroll) + auto& widget = w.widgets[widgetIndex]; + if (widget.type != WindowWidgetType::Scroll) continue; auto& scroll = w.scrolls[scrollIndex]; @@ -985,13 +984,13 @@ namespace OpenRCT2::Ui::Windows height++; scrollPositionChanged = 0; - if ((widget->content & SCROLL_HORIZONTAL) && width != scroll.contentWidth) + if ((widget.content & SCROLL_HORIZONTAL) && width != scroll.contentWidth) { scrollPositionChanged = 1; scroll.contentWidth = width; } - if ((widget->content & SCROLL_VERTICAL) && height != scroll.contentHeight) + if ((widget.content & SCROLL_VERTICAL) && height != scroll.contentHeight) { scrollPositionChanged = 1; scroll.contentHeight = height; @@ -1011,16 +1010,12 @@ namespace OpenRCT2::Ui::Windows */ void WindowInitScrollWidgets(WindowBase& w) { - Widget* widget; - int32_t widget_index, scroll_index; - - widget_index = 0; - scroll_index = 0; - for (widget = w.widgets; widget->type != WindowWidgetType::Last; widget++) + int32_t scroll_index{}; + for (WidgetIndex widgetIndex = 0; widgetIndex < w.widgets.size(); widgetIndex++) { - if (widget->type != WindowWidgetType::Scroll) + auto& widget = w.widgets[widgetIndex]; + if (widget.type != WindowWidgetType::Scroll) { - widget_index++; continue; } @@ -1032,14 +1027,12 @@ namespace OpenRCT2::Ui::Windows scroll.contentOffsetY = 0; scroll.contentHeight = scrollSize.height + 1; - if (widget->content & SCROLL_HORIZONTAL) + if (widget.content & SCROLL_HORIZONTAL) scroll.flags |= HSCROLLBAR_VISIBLE; - if (widget->content & SCROLL_VERTICAL) + if (widget.content & SCROLL_VERTICAL) scroll.flags |= VSCROLLBAR_VISIBLE; - WidgetScrollUpdateThumbs(w, widget_index); - - widget_index++; + WidgetScrollUpdateThumbs(w, widgetIndex); scroll_index++; } } @@ -1312,30 +1305,27 @@ namespace OpenRCT2::Ui::Windows */ void WindowDrawWidgets(WindowBase& w, DrawPixelInfo& dpi) { - Widget* widget; - WidgetIndex widgetIndex; - if ((w.flags & WF_TRANSPARENT) && !(w.flags & WF_NO_BACKGROUND)) GfxFilterRect( dpi, { w.windowPos, w.windowPos + ScreenCoordsXY{ w.width - 1, w.height - 1 } }, FilterPaletteID::Palette51); // todo: some code missing here? Between 006EB18C and 006EB260 - - widgetIndex = 0; - for (widget = w.widgets; widget->type != WindowWidgetType::Last; widget++) + for (WidgetIndex widgetIndex = 0; widgetIndex < w.widgets.size(); widgetIndex++) { - if (widget->IsVisible()) + auto& widget = w.widgets[widgetIndex]; + if (!widget.IsVisible()) { - // Check if widget is outside the draw region - if (w.windowPos.x + widget->left < dpi.x + dpi.width && w.windowPos.x + widget->right >= dpi.x) + continue; + } + + // Check if widget is outside the draw region + if (w.windowPos.x + widget.left < dpi.x + dpi.width && w.windowPos.x + widget.right >= dpi.x) + { + if (w.windowPos.y + widget.top < dpi.y + dpi.height && w.windowPos.y + widget.bottom >= dpi.y) { - if (w.windowPos.y + widget->top < dpi.y + dpi.height && w.windowPos.y + widget->bottom >= dpi.y) - { - w.OnDrawWidget(widgetIndex, dpi); - } + w.OnDrawWidget(widgetIndex, dpi); } } - widgetIndex++; } // todo: something missing here too? Between 006EC32B and 006EC369 diff --git a/src/openrct2-ui/interface/Window.h b/src/openrct2-ui/interface/Window.h index 6b2000da8c..d5003c07c0 100644 --- a/src/openrct2-ui/interface/Window.h +++ b/src/openrct2-ui/interface/Window.h @@ -14,41 +14,44 @@ struct TextInputSession; -struct Window : WindowBase +namespace OpenRCT2 { - virtual void OnDraw(DrawPixelInfo& dpi) override; - virtual void OnDrawWidget(WidgetIndex widgetIndex, DrawPixelInfo& dpi) override; + struct Window : WindowBase + { + void OnDraw(DrawPixelInfo& dpi) override; + void OnDrawWidget(WidgetIndex widgetIndex, DrawPixelInfo& dpi) override; - void ScrollToViewport(); - void InitScrollWidgets(); - void InvalidateWidget(WidgetIndex widgetIndex); - bool IsWidgetDisabled(WidgetIndex widgetIndex) const; - bool IsWidgetPressed(WidgetIndex widgetIndex) const; - void SetWidgetEnabled(WidgetIndex widgetIndex, bool value); - void SetWidgetDisabled(WidgetIndex widgetIndex, bool value); - void SetWidgetDisabledAndInvalidate(WidgetIndex widgetIndex, bool value); - void SetWidgetPressed(WidgetIndex widgetIndex, bool value); - void SetCheckboxValue(WidgetIndex widgetIndex, bool value); - void DrawWidgets(DrawPixelInfo& dpi); - void Close(); - void CloseOthers(); - void CloseOthersOfThisClass(); - CloseWindowModifier GetCloseModifier(); - void TextInputOpen( - WidgetIndex callWidget, StringId title, StringId description, const Formatter& descriptionArgs, StringId existingText, - uintptr_t existingArgs, int32_t maxLength); + void ScrollToViewport(); + void InitScrollWidgets(); + void InvalidateWidget(WidgetIndex widgetIndex); + bool IsWidgetDisabled(WidgetIndex widgetIndex) const; + bool IsWidgetPressed(WidgetIndex widgetIndex) const; + void SetWidgetEnabled(WidgetIndex widgetIndex, bool value); + void SetWidgetDisabled(WidgetIndex widgetIndex, bool value); + void SetWidgetDisabledAndInvalidate(WidgetIndex widgetIndex, bool value); + void SetWidgetPressed(WidgetIndex widgetIndex, bool value); + void SetCheckboxValue(WidgetIndex widgetIndex, bool value); + void DrawWidgets(DrawPixelInfo& dpi); + void Close(); + void CloseOthers(); + void CloseOthersOfThisClass(); + CloseWindowModifier GetCloseModifier(); + void TextInputOpen( + WidgetIndex callWidget, StringId title, StringId description, const Formatter& descriptionArgs, + StringId existingText, uintptr_t existingArgs, int32_t maxLength); - void ResizeFrame(); - void ResizeFrameWithPage(); + void ResizeFrame(); + void ResizeFrameWithPage(); - void ResizeSpinner(WidgetIndex widgetIndex, const ScreenCoordsXY& origin, const ScreenSize& size); - void ResizeDropdown(WidgetIndex widgetIndex, const ScreenCoordsXY& origin, const ScreenSize& size); -}; + void ResizeSpinner(WidgetIndex widgetIndex, const ScreenCoordsXY& origin, const ScreenSize& size); + void ResizeDropdown(WidgetIndex widgetIndex, const ScreenCoordsXY& origin, const ScreenSize& size); + }; -void WindowAllWheelInput(); -void ApplyScreenSaverLockSetting(); -void WindowAlignTabs(WindowBase* w, WidgetIndex start_tab_id, WidgetIndex end_tab_id); -ScreenCoordsXY WindowGetViewportSoundIconPos(WindowBase& w); + void WindowAllWheelInput(); + void ApplyScreenSaverLockSetting(); + void WindowAlignTabs(WindowBase* w, WidgetIndex start_tab_id, WidgetIndex end_tab_id); + ScreenCoordsXY WindowGetViewportSoundIconPos(WindowBase& w); +} // namespace OpenRCT2 namespace OpenRCT2::Ui::Windows { diff --git a/src/openrct2-ui/ride/Construction.h b/src/openrct2-ui/ride/Construction.h index 14a732369c..519704e59f 100644 --- a/src/openrct2-ui/ride/Construction.h +++ b/src/openrct2-ui/ride/Construction.h @@ -132,6 +132,10 @@ namespace OpenRCT2 TrackElemType::LeftLargeZeroGRollDown, TrackElemType::RightLargeZeroGRollUp, TrackElemType::RightLargeZeroGRollDown, + TrackElemType::LeftEighthDiveLoopUpToOrthogonal, + TrackElemType::LeftEighthDiveLoopDownToDiag, + TrackElemType::RightEighthDiveLoopUpToOrthogonal, + TrackElemType::RightEighthDiveLoopDownToDiag, TrackElemType::LeftFlyerLargeHalfLoopUninvertedUp, TrackElemType::LeftFlyerLargeHalfLoopInvertedDown, TrackElemType::LeftFlyerLargeHalfLoopInvertedUp, @@ -144,7 +148,7 @@ namespace OpenRCT2 constexpr size_t DropdownLength = DropdownOrder.size(); // Update the magic number with the current number of track elements to silence - static_assert(EnumValue(TrackElemType::Count) == 341, "Reminder to add new track element to special dropdown list"); + static_assert(EnumValue(TrackElemType::Count) == 349, "Reminder to add new track element to special dropdown list"); constexpr bool TrackPieceDirectionIsDiagonal(const uint8_t direction) { diff --git a/src/openrct2-ui/scripting/CustomListView.cpp b/src/openrct2-ui/scripting/CustomListView.cpp index 1e66098e52..c7841755d9 100644 --- a/src/openrct2-ui/scripting/CustomListView.cpp +++ b/src/openrct2-ui/scripting/CustomListView.cpp @@ -830,16 +830,17 @@ std::optional CustomListView::GetItemIndexAt(const ScreenCoordsXY& po return result; } -Widget* CustomListView::GetWidget() const +OpenRCT2::Widget* CustomListView::GetWidget() const { size_t scrollIndex = 0; - for (auto widget = ParentWindow->widgets; widget->type != WindowWidgetType::Last; widget++) + for (WidgetIndex widgetIndex = 0; widgetIndex < ParentWindow->widgets.size(); widgetIndex++) { - if (widget->type == WindowWidgetType::Scroll) + auto& widget = ParentWindow->widgets[widgetIndex]; + if (widget.type == WindowWidgetType::Scroll) { if (scrollIndex == ScrollIndex) { - return widget; + return &widget; } scrollIndex++; } diff --git a/src/openrct2-ui/scripting/CustomMenu.cpp b/src/openrct2-ui/scripting/CustomMenu.cpp index cb2756ebc1..6b0548b0cc 100644 --- a/src/openrct2-ui/scripting/CustomMenu.cpp +++ b/src/openrct2-ui/scripting/CustomMenu.cpp @@ -272,9 +272,10 @@ namespace OpenRCT2::Scripting auto toolbarWindow = windowMgr->FindByClass(WindowClass::TopToolbar); if (toolbarWindow != nullptr) { - // Use a widget that does not exist on top toolbar but also make sure it isn't -1 as that - // prevents abort from being called. - WidgetIndex widgetIndex = -2; + // Use a widget that does not exist on top toolbar but also make sure it isn't + // kWidgetIndexNull, as that prevents abort from being called. + // TODO: refactor this to not leech on the top toolbar. + WidgetIndex widgetIndex = 0xFFFE; ToolCancel(); ToolSet(*toolbarWindow, widgetIndex, static_cast(customTool.Cursor)); ActiveCustomTool = std::move(customTool); diff --git a/src/openrct2-ui/scripting/CustomWindow.cpp b/src/openrct2-ui/scripting/CustomWindow.cpp index c61a1ba233..c89f8ce91c 100644 --- a/src/openrct2-ui/scripting/CustomWindow.cpp +++ b/src/openrct2-ui/scripting/CustomWindow.cpp @@ -218,6 +218,21 @@ namespace OpenRCT2::Ui::Windows result.imageFrameCount = AsOrDefault(dukImage["frameCount"], 0); result.imageFrameDuration = AsOrDefault(dukImage["frameDuration"], 0); + if (dukImage["primaryColour"].type() == DukValue::Type::NUMBER) + { + result.imageFrameBase = result.imageFrameBase.WithPrimary(dukImage["primaryColour"].as_uint()); + + if (dukImage["secondaryColour"].type() == DukValue::Type::NUMBER) + { + result.imageFrameBase = result.imageFrameBase.WithSecondary(dukImage["secondaryColour"].as_uint()); + + if (dukImage["tertiaryColour"].type() == DukValue::Type::NUMBER) + { + result.imageFrameBase = result.imageFrameBase.WithTertiary(dukImage["tertiaryColour"].as_uint()); + } + } + } + auto dukCoord = dukImage["offset"]; if (dukCoord.type() == DukValue::Type::OBJECT) { @@ -459,9 +474,9 @@ namespace OpenRCT2::Ui::Windows // Since the plugin may alter widget positions and sizes during an update event, // we need to force an update for all list view scrollbars WidgetIndex widgetIndex = 0; - for (auto widget = widgets; widget->type != WindowWidgetType::Last; widget++) + for (auto& widget : widgets) { - if (widget->type == WindowWidgetType::Scroll) + if (widget.type == WindowWidgetType::Scroll) { WidgetScrollUpdateThumbs(*this, widgetIndex); } @@ -496,13 +511,13 @@ namespace OpenRCT2::Ui::Windows ft.Add(desc.Title.c_str()); size_t scrollIndex = 0; - for (auto widget = widgets; widget->type != WindowWidgetType::Last; widget++) + for (const auto& widget : widgets) { - if (widget->type == WindowWidgetType::Scroll) + if (widget.type == WindowWidgetType::Scroll) { auto& listView = _info.ListViews[scrollIndex]; - auto wwidth = widget->width() + 1 - 2; - auto wheight = widget->height() + 1 - 2; + auto wwidth = widget.width() + 1 - 2; + auto wheight = widget.height() + 1 - 2; if (listView.GetScrollbars() == ScrollbarType::Horizontal || listView.GetScrollbars() == ScrollbarType::Both) { @@ -765,9 +780,9 @@ namespace OpenRCT2::Ui::Windows std::optional GetViewportWidgetIndex() { WidgetIndex widgetIndex = 0; - for (auto widget = widgets; widget->type != WindowWidgetType::Last; widget++) + for (auto& widget : widgets) { - if (widget->type == WindowWidgetType::Viewport) + if (widget.type == WindowWidgetType::Viewport) { return widgetIndex; } @@ -928,8 +943,7 @@ namespace OpenRCT2::Ui::Windows } } - widgetList.push_back(kWidgetsEnd); - widgets = widgetList.data(); + SetWidgets(widgetList); WindowInitScrollWidgets(*this); UpdateViewport(); diff --git a/src/openrct2-ui/scripting/ScWidget.hpp b/src/openrct2-ui/scripting/ScWidget.hpp index 4f9ec52734..aeb056e531 100644 --- a/src/openrct2-ui/scripting/ScWidget.hpp +++ b/src/openrct2-ui/scripting/ScWidget.hpp @@ -117,8 +117,6 @@ namespace OpenRCT2::Scripting return "progress_bar"; case WindowWidgetType::Custom: return "custom"; - case WindowWidgetType::Last: - return "last"; } } return "unknown"; diff --git a/src/openrct2-ui/scripting/ScWindow.hpp b/src/openrct2-ui/scripting/ScWindow.hpp index fee0966ba1..872ac02bd2 100644 --- a/src/openrct2-ui/scripting/ScWindow.hpp +++ b/src/openrct2-ui/scripting/ScWindow.hpp @@ -218,11 +218,9 @@ namespace OpenRCT2::Scripting auto w = GetWindow(); if (w != nullptr) { - WidgetIndex widgetIndex = 0; - for (auto widget = w->widgets; widget->type != WindowWidgetType::Last; widget++) + for (WidgetIndex widgetIndex = 0; widgetIndex < w->widgets.size(); widgetIndex++) { result.push_back(ScWidget::ToDukValue(ctx, w, widgetIndex)); - widgetIndex++; } } return result; diff --git a/src/openrct2-ui/windows/About.cpp b/src/openrct2-ui/windows/About.cpp index 94996f277c..b85113f923 100644 --- a/src/openrct2-ui/windows/About.cpp +++ b/src/openrct2-ui/windows/About.cpp @@ -63,7 +63,7 @@ namespace OpenRCT2::Ui::Windows MakeRemapWidget({ 94, 17 }, { 91, TABHEIGHT - 16 }, WindowWidgetType::Tab, WindowColour::Secondary, SPR_TAB_LARGE) // clang-format off - static Widget _windowAboutOpenRCT2Widgets[] = { + static constexpr Widget _windowAboutOpenRCT2Widgets[] = { WIDGETS_MAIN, MakeWidget({10, 60}, {WW - 20, 20}, WindowWidgetType::LabelCentred, WindowColour::Secondary, STR_ABOUT_OPENRCT2_DESCRIPTION), // Introduction MakeWidget({30, 90}, {128, 128}, WindowWidgetType::Placeholder, WindowColour::Secondary, STR_NONE), // OpenRCT2 Logo @@ -73,16 +73,14 @@ namespace OpenRCT2::Ui::Windows MakeWidget({168, 115 + 40}, {200, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_CHANGELOG_ELLIPSIS), // changelog button MakeWidget({168, 115 + 60}, {200, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_JOIN_DISCORD ), // "join discord" button MakeWidget({168, 115 + 80}, {200, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_CONTRIBUTORS_WINDOW_BUTTON), // "contributors" button - kWidgetsEnd, }; // clang-format on - static Widget _windowAboutRCT2Widgets[] = { + static constexpr Widget _windowAboutRCT2Widgets[] = { WIDGETS_MAIN, - kWidgetsEnd, }; - static Widget* _windowAboutPageWidgets[] = { + static constexpr std::span _windowAboutPageWidgets[] = { _windowAboutOpenRCT2Widgets, _windowAboutRCT2Widgets, }; @@ -92,9 +90,6 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = _windowAboutOpenRCT2Widgets; - - WindowInitScrollWidgets(*this); SetPage(WINDOW_ABOUT_PAGE_OPENRCT2); } @@ -174,7 +169,7 @@ namespace OpenRCT2::Ui::Windows page = p; frame_no = 0; pressed_widgets = 0; - widgets = _windowAboutPageWidgets[p]; + SetWidgets(_windowAboutPageWidgets[p]); switch (p) { @@ -186,7 +181,7 @@ namespace OpenRCT2::Ui::Windows break; } - WindowInitScrollWidgets(*this); + InitScrollWidgets(); Invalidate(); } @@ -215,7 +210,6 @@ namespace OpenRCT2::Ui::Windows if (OpenRCT2::GetContext()->HasNewVersionInfo()) { widgets[WIDX_NEW_VERSION].type = WindowWidgetType::Button; - _windowAboutOpenRCT2Widgets[WIDX_NEW_VERSION].type = WindowWidgetType::Button; } // Draw the rest of the text diff --git a/src/openrct2-ui/windows/AssetPacks.cpp b/src/openrct2-ui/windows/AssetPacks.cpp index 622a80f3f3..5d0aa86878 100644 --- a/src/openrct2-ui/windows/AssetPacks.cpp +++ b/src/openrct2-ui/windows/AssetPacks.cpp @@ -40,7 +40,7 @@ namespace OpenRCT2::Ui::Windows }; // clang-format off - static Widget WindowAssetPacksWidgets[] = { + static constexpr Widget WindowAssetPacksWidgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), MakeWidget({ 0, 0 }, { 0, 0 }, WindowWidgetType::LabelCentred, WindowColour::Secondary, STR_HIGH_PRIORITY), MakeWidget({ 0, 0 }, { 0, 147 }, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_VERTICAL), @@ -48,7 +48,6 @@ namespace OpenRCT2::Ui::Windows MakeWidget({ 0, 0 }, { 0, 0 }, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_G2_ARROW_UP), STR_INCREASE_PRIOTITY_TIP), MakeWidget({ 0, 0 }, { 0, 0 }, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_G2_ARROW_DOWN), STR_DECREASE_PRIOTITY_TIP), MakeWidget({ 0, 0 }, { 0, 0 }, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_G2_RELOAD), STR_RELOAD_ASSET_PACKS_TIP), - kWidgetsEnd, }; // clang-format on @@ -63,7 +62,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = WindowAssetPacksWidgets; + SetWidgets(WindowAssetPacksWidgets); WindowInitScrollWidgets(*this); } diff --git a/src/openrct2-ui/windows/Banner.cpp b/src/openrct2-ui/windows/Banner.cpp index e94402770e..0d675ba2d5 100644 --- a/src/openrct2-ui/windows/Banner.cpp +++ b/src/openrct2-ui/windows/Banner.cpp @@ -63,7 +63,7 @@ namespace OpenRCT2::Ui::Windows STR_TEXT_COLOUR_PALESILVER, }; - static Widget window_banner_widgets[] = { + static constexpr Widget window_banner_widgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), MakeWidget({ 3, 17}, {85, 60}, WindowWidgetType::Viewport, WindowColour::Secondary, 0x0FFFFFFFE ), // tab content panel MakeWidget({WW - 25, 19}, {24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_RENAME), STR_CHANGE_BANNER_TEXT_TIP ), // change banner button @@ -72,7 +72,6 @@ namespace OpenRCT2::Ui::Windows MakeWidget({ 5, WH - 16}, {12, 12}, WindowWidgetType::ColourBtn, WindowColour::Secondary, 0xFFFFFFFF, STR_SELECT_MAIN_SIGN_COLOUR_TIP), // high money MakeWidget({ 43, WH - 16}, {39, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary ), // high money MakeWidget({ 70, WH - 15}, {11, 10}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH, STR_SELECT_TEXT_COLOUR_TIP ), // high money - kWidgetsEnd, }; // clang-format on @@ -83,10 +82,10 @@ namespace OpenRCT2::Ui::Windows void CreateViewport() { - Widget* viewportWidget = &window_banner_widgets[WIDX_VIEWPORT]; + const auto& viewportWidget = window_banner_widgets[WIDX_VIEWPORT]; ViewportCreate( - this, windowPos + ScreenCoordsXY{ viewportWidget->left + 1, viewportWidget->top + 1 }, - (viewportWidget->width()) - 1, (viewportWidget->height()) - 1, Focus(_bannerViewPos)); + this, windowPos + ScreenCoordsXY{ viewportWidget.left + 1, viewportWidget.top + 1 }, + (viewportWidget.width()) - 1, (viewportWidget.height()) - 1, Focus(_bannerViewPos)); if (viewport != nullptr) viewport->flags = Config::Get().general.AlwaysShowGridlines ? VIEWPORT_FLAG_GRIDLINES : VIEWPORT_FLAG_NONE; @@ -131,7 +130,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = window_banner_widgets; + SetWidgets(window_banner_widgets); WindowInitScrollWidgets(*this); } @@ -279,13 +278,13 @@ namespace OpenRCT2::Ui::Windows { return; } - Widget* colourBtn = &window_banner_widgets[WIDX_MAIN_COLOUR]; - colourBtn->type = WindowWidgetType::Empty; + Widget& colourBtn = widgets[WIDX_MAIN_COLOUR]; + colourBtn.type = WindowWidgetType::Empty; auto* bannerEntry = OpenRCT2::ObjectManager::GetObjectEntry(banner->type); if (bannerEntry != nullptr && (bannerEntry->flags & BANNER_ENTRY_FLAG_HAS_PRIMARY_COLOUR)) { - colourBtn->type = WindowWidgetType::ColourBtn; + colourBtn.type = WindowWidgetType::ColourBtn; } pressed_widgets &= ~(1uLL << WIDX_BANNER_NO_ENTRY); disabled_widgets &= ~( @@ -296,9 +295,9 @@ namespace OpenRCT2::Ui::Windows disabled_widgets |= (1uLL << WIDX_BANNER_TEXT) | (1uLL << WIDX_TEXT_COLOUR_DROPDOWN) | (1uLL << WIDX_TEXT_COLOUR_DROPDOWN_BUTTON); } - colourBtn->image = GetColourButtonImage(banner->colour); - Widget* dropDownWidget = &window_banner_widgets[WIDX_TEXT_COLOUR_DROPDOWN]; - dropDownWidget->text = BannerColouredTextFormats[banner->text_colour]; + colourBtn.image = GetColourButtonImage(banner->colour); + Widget& dropDownWidget = widgets[WIDX_TEXT_COLOUR_DROPDOWN]; + dropDownWidget.text = BannerColouredTextFormats[banner->text_colour]; } void OnResize() override diff --git a/src/openrct2-ui/windows/Changelog.cpp b/src/openrct2-ui/windows/Changelog.cpp index 7de4e4703e..a77331bdbf 100644 --- a/src/openrct2-ui/windows/Changelog.cpp +++ b/src/openrct2-ui/windows/Changelog.cpp @@ -47,7 +47,6 @@ namespace OpenRCT2::Ui::Windows MakeWidget({0, 14}, {500, 382}, WindowWidgetType::Resize, WindowColour::Secondary ), // content panel MakeWidget({3, 16}, {495, 366}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_BOTH ), // scroll area MakeWidget({3, 473}, {300, 14}, WindowWidgetType::Placeholder, WindowColour::Secondary, STR_NEW_RELEASE_DOWNLOAD_PAGE), // changelog button - kWidgetsEnd, }; // clang-format on @@ -125,7 +124,7 @@ namespace OpenRCT2::Ui::Windows void OnOpen() override { - widgets = _windowChangelogWidgets; + SetWidgets(_windowChangelogWidgets); WindowInitScrollWidgets(*this); min_width = MIN_WW; diff --git a/src/openrct2-ui/windows/Cheats.cpp b/src/openrct2-ui/windows/Cheats.cpp index 91773863e4..f294b55ac6 100644 --- a/src/openrct2-ui/windows/Cheats.cpp +++ b/src/openrct2-ui/windows/Cheats.cpp @@ -219,7 +219,7 @@ static constexpr int32_t TAB_START = 3; MakeTab ({158, 17}, STR_RIDE_CHEATS_TIP ), /* tab 4 */ \ MakeTab ({189, 17}, STR_WEATHER_NATURE_CHEATS_TIP ) /* tab 7 */ -static Widget window_cheats_money_widgets[] = +static constexpr Widget window_cheats_money_widgets[] = { MAIN_CHEATS_WIDGETS, MakeWidget ({ 11, 48}, CHEAT_BUTTON, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_MAKE_PARK_NO_MONEY), // No money @@ -228,10 +228,9 @@ static Widget window_cheats_money_widgets[] = MakeWidget ({ 11, 111}, CHEAT_BUTTON, WindowWidgetType::Button, WindowColour::Secondary, STR_ADD_MONEY ), // add money MakeWidget ({127, 111}, CHEAT_BUTTON, WindowWidgetType::Button, WindowColour::Secondary, STR_SET_MONEY ), // set money MakeWidget ({ 11, 145}, CHEAT_BUTTON, WindowWidgetType::Button, WindowColour::Secondary, STR_CHEAT_CLEAR_LOAN ), // Clear loan - kWidgetsEnd, }; -static Widget window_cheats_date_widgets[] = +static constexpr Widget window_cheats_date_widgets[] = { MAIN_CHEATS_WIDGETS, MakeWidget ({ 5, 48}, {238, 99} , WindowWidgetType::Groupbox, WindowColour::Secondary, STR_DATE_SET ), // Date group @@ -240,10 +239,9 @@ static Widget window_cheats_date_widgets[] = MakeSpinnerWidgets({120, 103}, CHEAT_SPINNER, WindowWidgetType::Spinner, WindowColour::Secondary ), // Day box MakeWidget ({ 11, 122}, CHEAT_BUTTON, WindowWidgetType::Button, WindowColour::Secondary, STR_DATE_SET ), // Set Date MakeWidget ({127, 122}, CHEAT_BUTTON, WindowWidgetType::Button, WindowColour::Secondary, STR_DATE_RESET), // Reset Date - kWidgetsEnd, }; -static Widget window_cheats_guests_widgets[] = +static constexpr Widget window_cheats_guests_widgets[] = { MAIN_CHEATS_WIDGETS, MakeWidget({ 11, 48}, CHEAT_BUTTON, WindowWidgetType::Button, WindowColour::Secondary, STR_CHEAT_LARGE_TRAM_GUESTS, STR_CHEAT_LARGE_TRAM_GUESTS_TIP), // large tram @@ -278,11 +276,9 @@ static Widget window_cheats_guests_widgets[] = MakeWidget({ 11, 380+1}, CHEAT_CHECK, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_CHEAT_IGNORE_PRICE, STR_CHEAT_IGNORE_PRICE_TIP ), // guests ignore price MakeWidget({ 11, 397+1}, CHEAT_CHECK, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_CHEAT_DISABLE_VANDALISM, STR_CHEAT_DISABLE_VANDALISM_TIP), // disable vandalism MakeWidget({ 11, 414+1}, CHEAT_CHECK, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_CHEAT_DISABLE_LITTERING, STR_CHEAT_DISABLE_LITTERING_TIP), // disable littering - - kWidgetsEnd, }; -static Widget window_cheats_staff_widgets[] = +static constexpr Widget window_cheats_staff_widgets[] = { MAIN_CHEATS_WIDGETS, MakeWidget ({ 5, 357-309}, {238, 35}, WindowWidgetType::Groupbox, WindowColour::Secondary, STR_CHEAT_STAFF_GROUP ), // Staff group @@ -296,11 +292,9 @@ static Widget window_cheats_staff_widgets[] = MakeWidget ({127, 292-168}, CHEAT_BUTTON, WindowWidgetType::Button, WindowColour::Secondary, STR_CHEAT_MOWED_GRASS ), // Mowed grass MakeWidget ({ 11, 313-168}, CHEAT_BUTTON, WindowWidgetType::Button, WindowColour::Secondary, STR_CHEAT_WATER_PLANTS ), // Water plants MakeWidget ({ 11, 334-164}, CHEAT_CHECK, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_CHEAT_DISABLE_PLANT_AGING, STR_CHEAT_DISABLE_PLANT_AGING_TIP ), // Disable plant ageing - - kWidgetsEnd, }; -static Widget window_cheats_park_widgets[] = +static constexpr Widget window_cheats_park_widgets[] = { MAIN_CHEATS_WIDGETS, MakeWidget ({ 5, 48}, {238, 60}, WindowWidgetType::Groupbox, WindowColour::Secondary, STR_CHEAT_GENERAL_GROUP ), // General group @@ -319,11 +313,9 @@ static Widget window_cheats_park_widgets[] = MakeWidget ({ 11, 207}, CHEAT_CHECK, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_CHEAT_BUILD_IN_PAUSE_MODE, STR_CHEAT_BUILD_IN_PAUSE_MODE_TIP ), // Build in pause mode MakeWidget ({ 11, 224}, CHEAT_CHECK, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_CHEAT_ALLOW_PATH_AS_QUEUE, STR_CHEAT_ALLOW_PATH_AS_QUEUE_TIP ), // Allow regular footpaths as queue path MakeWidget ({ 11, 241}, CHEAT_CHECK, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_CHEAT_ALLOW_SPECIAL_COLOUR_SCHEMES, STR_CHEAT_ALLOW_SPECIAL_COLOUR_SCHEMES_TIP), // Allow special colours in dropdown - - kWidgetsEnd, }; -static Widget window_cheats_rides_widgets[] = +static constexpr Widget window_cheats_rides_widgets[] = { MAIN_CHEATS_WIDGETS, MakeWidget({ 11, 48}, CHEAT_BUTTON, WindowWidgetType::Button, WindowColour::Secondary, STR_CHEAT_FIX_ALL_RIDES, STR_CHEAT_FIX_ALL_RIDES_TIP ), // Fix all rides @@ -349,10 +341,9 @@ static Widget window_cheats_rides_widgets[] = MakeWidget({ 11, 325}, CHEAT_CHECK, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_CHEAT_SHOW_VEHICLES_FROM_OTHER_TRACK_TYPES ), // Show vehicles from other track types MakeWidget({ 11, 342}, CHEAT_CHECK, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_CHEAT_DISABLE_TRAIN_LENGTH_LIMIT, STR_CHEAT_DISABLE_TRAIN_LENGTH_LIMIT_TIP ), // Disable train length limits MakeWidget({ 11, 359}, CHEAT_CHECK, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_CHEAT_IGNORE_RESEARCH_STATUS, STR_CHEAT_IGNORE_RESEARCH_STATUS_TIP ), // Ignore Research Status - kWidgetsEnd, }; -static Widget window_cheats_weather_widgets[] = +static constexpr Widget window_cheats_weather_widgets[] = { MAIN_CHEATS_WIDGETS, MakeWidget ({ 5, 48}, {238, 50}, WindowWidgetType::Groupbox, WindowColour::Secondary, STR_CHEAT_WEATHER_GROUP ), // Weather group @@ -362,10 +353,9 @@ static Widget window_cheats_weather_widgets[] = MakeWidget ({ 5, 102}, {238, 37}, WindowWidgetType::Groupbox, WindowColour::Secondary, STR_FAUNA ), // Fauna group MakeWidget ({ 11, 115}, CHEAT_BUTTON, WindowWidgetType::Button, WindowColour::Secondary, STR_CREATE_DUCKS, STR_CREATE_DUCKS_TIP ), // Create ducks MakeWidget ({127, 115}, CHEAT_BUTTON, WindowWidgetType::Button, WindowColour::Secondary, STR_REMOVE_DUCKS, STR_REMOVE_DUCKS_TIP ), // Remove ducks - kWidgetsEnd, }; -static Widget *window_cheats_page_widgets[] = +static constexpr std::span window_cheats_page_widgets[] = { window_cheats_money_widgets, window_cheats_date_widgets, @@ -512,13 +502,6 @@ static StringId window_cheats_page_titles[] = { void OnPrepareDraw() override { - auto* targetWidgets = window_cheats_page_widgets[page]; - if (widgets != targetWidgets) - { - widgets = targetWidgets; - WindowInitScrollWidgets(*this); - } - pressed_widgets = 0; disabled_widgets = 0; @@ -592,11 +575,16 @@ static StringId window_cheats_page_titles[] = { } // Current weather - window_cheats_weather_widgets[WIDX_WEATHER].text = WeatherTypes[EnumValue(gameState.ClimateCurrent.Weather)]; + if (page == WINDOW_CHEATS_PAGE_WEATHER) + { + widgets[WIDX_WEATHER].text = WeatherTypes[EnumValue(gameState.ClimateCurrent.Weather)]; + } // Staff speed - window_cheats_staff_widgets[WIDX_STAFF_SPEED].text = _staffSpeedNames[EnumValue( - gameState.Cheats.selectedStaffSpeed)]; + if (page == WINDOW_CHEATS_PAGE_STAFF) + { + widgets[WIDX_STAFF_SPEED].text = _staffSpeedNames[EnumValue(gameState.Cheats.selectedStaffSpeed)]; + } if (gScreenFlags & SCREEN_FLAGS_EDITOR) { @@ -753,18 +741,18 @@ static StringId window_cheats_page_titles[] = { hold_down_widgets = window_cheats_page_hold_down_widgets[p]; pressed_widgets = 0; - widgets = window_cheats_page_widgets[p]; + SetWidgets(window_cheats_page_widgets[p]); auto maxY = 0; - auto* widget = &widgets[WIDX_TAB_CONTENT]; - while (widget->type != WindowWidgetType::Last) + for (WidgetIndex widgetIdx = WIDX_TAB_CONTENT; widgetIdx < widgets.size(); widgetIdx++) { - maxY = std::max(maxY, widget->bottom); - widget++; + auto& widget = widgets[widgetIdx]; + maxY = std::max(maxY, widget.bottom); } maxY += 6; Invalidate(); + WindowInitScrollWidgets(*this); height = maxY; widgets[WIDX_BACKGROUND].bottom = maxY - 1; widgets[WIDX_PAGE_BACKGROUND].bottom = maxY - 1; diff --git a/src/openrct2-ui/windows/ClearScenery.cpp b/src/openrct2-ui/windows/ClearScenery.cpp index 07340aa792..7749b36ef7 100644 --- a/src/openrct2-ui/windows/ClearScenery.cpp +++ b/src/openrct2-ui/windows/ClearScenery.cpp @@ -44,7 +44,7 @@ namespace OpenRCT2::Ui::Windows static constexpr ScreenSize CLEAR_SCENERY_BUTTON = { 24, 24 }; - static Widget window_clear_scenery_widgets[] = { + static constexpr Widget window_clear_scenery_widgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), MakeWidget( { 27, 17 }, { 44, 32 }, WindowWidgetType::ImgBtn, WindowColour::Primary, SPR_LAND_TOOL_SIZE_0, @@ -64,7 +64,6 @@ namespace OpenRCT2::Ui::Windows MakeRemapWidget( { 67, 53 }, CLEAR_SCENERY_BUTTON, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_G2_BUTTON_FOOTPATH, STR_CLEAR_SCENERY_REMOVE_FOOTPATHS_TIP), // footpaths - kWidgetsEnd, }; class CleanSceneryWindow final : public Window @@ -78,7 +77,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = window_clear_scenery_widgets; + SetWidgets(window_clear_scenery_widgets); hold_down_widgets = (1uLL << WIDX_INCREMENT) | (1uLL << WIDX_DECREMENT); WindowInitScrollWidgets(*this); WindowPushOthersBelow(*this); @@ -178,7 +177,7 @@ namespace OpenRCT2::Ui::Windows | (_clearLargeScenery ? (1uLL << WIDX_LARGE_SCENERY) : 0) | (_clearFootpath ? (1uLL << WIDX_FOOTPATH) : 0); // Update the preview image (for tool sizes up to 7) - window_clear_scenery_widgets[WIDX_PREVIEW].image = ImageId(LandTool::SizeToSpriteIndex(gLandToolSize)); + widgets[WIDX_PREVIEW].image = ImageId(LandTool::SizeToSpriteIndex(gLandToolSize)); } void OnDraw(DrawPixelInfo& dpi) override @@ -186,8 +185,8 @@ namespace OpenRCT2::Ui::Windows DrawWidgets(dpi); // Draw number for tool sizes bigger than 7 - ScreenCoordsXY screenCoords = { windowPos.x + window_clear_scenery_widgets[WIDX_PREVIEW].midX(), - windowPos.y + window_clear_scenery_widgets[WIDX_PREVIEW].midY() }; + ScreenCoordsXY screenCoords = { windowPos.x + widgets[WIDX_PREVIEW].midX(), + windowPos.y + widgets[WIDX_PREVIEW].midY() }; if (gLandToolSize > kLandToolMaximumSizeWithSprite) { auto ft = Formatter(); @@ -202,8 +201,8 @@ namespace OpenRCT2::Ui::Windows { auto ft = Formatter(); ft.Add(_clearSceneryCost); - screenCoords.x = window_clear_scenery_widgets[WIDX_PREVIEW].midX() + windowPos.x; - screenCoords.y = window_clear_scenery_widgets[WIDX_PREVIEW].bottom + windowPos.y + 5 + 27; + screenCoords.x = widgets[WIDX_PREVIEW].midX() + windowPos.x; + screenCoords.y = widgets[WIDX_PREVIEW].bottom + windowPos.y + 5 + 27; DrawTextBasic(dpi, screenCoords, STR_COST_AMOUNT, ft, { TextAlignment::CENTRE }); } } diff --git a/src/openrct2-ui/windows/CustomCurrency.cpp b/src/openrct2-ui/windows/CustomCurrency.cpp index 8392d986fc..ef5ae15b85 100644 --- a/src/openrct2-ui/windows/CustomCurrency.cpp +++ b/src/openrct2-ui/windows/CustomCurrency.cpp @@ -45,7 +45,6 @@ namespace OpenRCT2::Ui::Windows MakeWidget ({120, 50}, { 81, 11}, WindowWidgetType::Button, WindowColour::Secondary, STR_EMPTY ), MakeWidget ({220, 50}, {131, 11}, WindowWidgetType::DropdownMenu, WindowColour::Secondary ), MakeWidget ({339, 51}, { 11, 9}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH ), - kWidgetsEnd, }; // clang-format on @@ -54,7 +53,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = window_custom_currency_widgets; + SetWidgets(window_custom_currency_widgets); hold_down_widgets = (1uLL << WIDX_RATE_UP) | (1uLL << WIDX_RATE_DOWN); WindowInitScrollWidgets(*this); colours[0] = COLOUR_LIGHT_BROWN; @@ -208,15 +207,12 @@ namespace OpenRCT2::Ui::Windows DrawTextBasic(dpi, screenCoords, STR_CURRENCY_SYMBOL_TEXT, {}, { colours[1] }); - screenCoords = windowPos - + ScreenCoordsXY{ window_custom_currency_widgets[WIDX_SYMBOL_TEXT].left + 1, - window_custom_currency_widgets[WIDX_SYMBOL_TEXT].top }; + screenCoords = windowPos + ScreenCoordsXY{ widgets[WIDX_SYMBOL_TEXT].left + 1, widgets[WIDX_SYMBOL_TEXT].top }; DrawText(dpi, screenCoords, { colours[1] }, CurrencyDescriptors[EnumValue(CurrencyType::Custom)].symbol_unicode); auto drawPos = windowPos - + ScreenCoordsXY{ window_custom_currency_widgets[WIDX_AFFIX_DROPDOWN].left + 1, - window_custom_currency_widgets[WIDX_AFFIX_DROPDOWN].top }; + + ScreenCoordsXY{ widgets[WIDX_AFFIX_DROPDOWN].left + 1, widgets[WIDX_AFFIX_DROPDOWN].top }; StringId stringId = (CurrencyDescriptors[EnumValue(CurrencyType::Custom)].affix_unicode == CurrencyAffix::Prefix) ? STR_PREFIX : STR_SUFFIX; diff --git a/src/openrct2-ui/windows/DebugPaint.cpp b/src/openrct2-ui/windows/DebugPaint.cpp index 50bdd1a302..0973e14888 100644 --- a/src/openrct2-ui/windows/DebugPaint.cpp +++ b/src/openrct2-ui/windows/DebugPaint.cpp @@ -34,7 +34,7 @@ namespace OpenRCT2::Ui::Windows constexpr int32_t WINDOW_HEIGHT = 8 + (15 * 6) + 8; // clang-format off - static Widget window_debug_paint_widgets[] = { + static constexpr Widget window_debug_paint_widgets[] = { MakeWidget({0, 0}, {WINDOW_WIDTH, WINDOW_HEIGHT}, WindowWidgetType::Frame, WindowColour::Primary ), MakeWidget({8, 8 + 15 * 0}, { 185, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_DEBUG_PAINT_SHOW_WIDE_PATHS ), MakeWidget({8, 8 + 15 * 1}, { 185, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_DEBUG_PAINT_SHOW_BLOCKED_TILES ), @@ -42,7 +42,6 @@ namespace OpenRCT2::Ui::Windows MakeWidget({8, 8 + 15 * 3}, { 185, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_DEBUG_PAINT_SHOW_BOUND_BOXES ), MakeWidget({8, 8 + 15 * 4}, { 185, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_DEBUG_PAINT_SHOW_DIRTY_VISUALS ), MakeWidget({8, 8 + 15 * 5}, { 185, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_DEBUG_PAINT_STABLE_SORT ), - kWidgetsEnd, }; // clang-format on @@ -54,7 +53,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = window_debug_paint_widgets; + SetWidgets(window_debug_paint_widgets); InitScrollWidgets(); WindowPushOthersBelow(*this); diff --git a/src/openrct2-ui/windows/DemolishRidePrompt.cpp b/src/openrct2-ui/windows/DemolishRidePrompt.cpp index 2a5691fe19..1ae9cdc9b8 100644 --- a/src/openrct2-ui/windows/DemolishRidePrompt.cpp +++ b/src/openrct2-ui/windows/DemolishRidePrompt.cpp @@ -35,12 +35,11 @@ namespace OpenRCT2::Ui::Windows }; // clang-format off - static Widget window_ride_demolish_widgets[] = + static constexpr Widget window_ride_demolish_widgets[] = { WINDOW_SHIM_WHITE(STR_DEMOLISH_RIDE, WW, WH), MakeWidget({ 10, WH - 22}, {85, 14}, WindowWidgetType::Button, WindowColour::Primary, STR_DEMOLISH ), MakeWidget({WW - 95, WH - 22}, {85, 14}, WindowWidgetType::Button, WindowColour::Primary, STR_SAVE_PROMPT_CANCEL), - kWidgetsEnd, }; // clang-format on @@ -57,7 +56,7 @@ namespace OpenRCT2::Ui::Windows void OnOpen() override { - widgets = window_ride_demolish_widgets; + SetWidgets(window_ride_demolish_widgets); WindowInitScrollWidgets(*this); } diff --git a/src/openrct2-ui/windows/Dropdown.cpp b/src/openrct2-ui/windows/Dropdown.cpp index 34a87d4819..0a46a16f4c 100644 --- a/src/openrct2-ui/windows/Dropdown.cpp +++ b/src/openrct2-ui/windows/Dropdown.cpp @@ -41,9 +41,8 @@ namespace OpenRCT2::Ui::Windows WIDX_BACKGROUND, }; - static Widget window_dropdown_widgets[] = { + static constexpr Widget window_dropdown_widgets[] = { MakeWidget({ 0, 0 }, { 1, 1 }, WindowWidgetType::ImgBtn, WindowColour::Primary), - kWidgetsEnd, }; int32_t gDropdownNumItems; @@ -75,7 +74,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = window_dropdown_widgets; + SetWidgets(window_dropdown_widgets); // Input state gDropdownHighlightedIndex = -1; @@ -295,8 +294,8 @@ namespace OpenRCT2::Ui::Windows boundedScreenPos.x = std::max(0, screenWidth - ddWidth); if (screenPos.y + ddHeight > screenHeight) boundedScreenPos.y = std::max(0, screenHeight - ddHeight); - window_dropdown_widgets[WIDX_BACKGROUND].right = ddWidth; - window_dropdown_widgets[WIDX_BACKGROUND].bottom = ddHeight; + widgets[WIDX_BACKGROUND].right = ddWidth; + widgets[WIDX_BACKGROUND].bottom = ddHeight; Invalidate(); width = ddWidth + 1; diff --git a/src/openrct2-ui/windows/EditorBottomToolbar.cpp b/src/openrct2-ui/windows/EditorBottomToolbar.cpp index 3d66604bf8..47ccc32949 100644 --- a/src/openrct2-ui/windows/EditorBottomToolbar.cpp +++ b/src/openrct2-ui/windows/EditorBottomToolbar.cpp @@ -38,12 +38,11 @@ namespace OpenRCT2::Ui::Windows }; // clang-format off - static Widget _editorBottomToolbarWidgets[] = { + static constexpr Widget _editorBottomToolbarWidgets[] = { MakeWidget({ 0, 0}, {200, 34}, WindowWidgetType::ImgBtn, WindowColour::Primary), MakeWidget({ 2, 2}, {196, 30}, WindowWidgetType::FlatBtn, WindowColour::Primary), MakeWidget({440, 0}, {200, 34}, WindowWidgetType::ImgBtn, WindowColour::Primary), MakeWidget({442, 2}, {196, 30}, WindowWidgetType::FlatBtn, WindowColour::Primary), - kWidgetsEnd, }; // clang-format on @@ -62,7 +61,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = _editorBottomToolbarWidgets; + SetWidgets(_editorBottomToolbarWidgets); InitScrollWidgets(); SetAllSceneryItemsInvented(); diff --git a/src/openrct2-ui/windows/EditorInventionsList.cpp b/src/openrct2-ui/windows/EditorInventionsList.cpp index ca76110308..14819b9bc6 100644 --- a/src/openrct2-ui/windows/EditorInventionsList.cpp +++ b/src/openrct2-ui/windows/EditorInventionsList.cpp @@ -54,7 +54,7 @@ namespace OpenRCT2::Ui::Windows }; // clang-format off - static Widget _inventionListWidgets[] = { + static constexpr Widget _inventionListWidgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), MakeWidget({ 0, 43}, {600, 357}, WindowWidgetType::Resize, WindowColour::Secondary ), MakeTab ({ 3, 17} ), @@ -64,12 +64,10 @@ namespace OpenRCT2::Ui::Windows MakeWidget({375, 343}, {220, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_MOVE_ALL_TOP ), MakeWidget({375, 358}, {220, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_MOVE_ALL_BOTTOM ), MakeWidget({375, 373}, {220, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_RANDOM_SHUFFLE, STR_RANDOM_SHUFFLE_TIP), - kWidgetsEnd, }; - static Widget _inventionListDragWidgets[] = { + static constexpr Widget _inventionListDragWidgets[] = { MakeWidget({0, 0}, {150, 14}, WindowWidgetType::ImgBtn, WindowColour::Primary), - kWidgetsEnd, }; // clang-format on @@ -154,7 +152,7 @@ namespace OpenRCT2::Ui::Windows { ResearchRidesSetup(); - widgets = _inventionListWidgets; + SetWidgets(_inventionListWidgets); InitScrollWidgets(); selected_tab = 0; _selectedResearchItem = nullptr; @@ -611,7 +609,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = _inventionListDragWidgets; + SetWidgets(_inventionListDragWidgets); colours[1] = COLOUR_WHITE; } diff --git a/src/openrct2-ui/windows/EditorObjectSelection.cpp b/src/openrct2-ui/windows/EditorObjectSelection.cpp index 4c19602a2f..092e3e7de2 100644 --- a/src/openrct2-ui/windows/EditorObjectSelection.cpp +++ b/src/openrct2-ui/windows/EditorObjectSelection.cpp @@ -226,10 +226,8 @@ namespace OpenRCT2::Ui::Windows validate_global_widx(WC_EDITOR_OBJECT_SELECTION, WIDX_TAB_1); - static bool _window_editor_object_selection_widgets_initialised; - // clang-format off - static std::vector _window_editor_object_selection_widgets = { + static constexpr Widget _window_editor_object_selection_widgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), MakeWidget ({ 0, 43}, {WW, 357}, WindowWidgetType::Resize, WindowColour::Secondary ), MakeWidget ({ 4, 60}, {288, 277}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_VERTICAL ), @@ -251,8 +249,6 @@ namespace OpenRCT2::Ui::Windows MakeWidget ({700, 50}, { 24, 24}, WindowWidgetType::ImgBtn, WindowColour::Secondary, SPR_G2_RELOAD, STR_RELOAD_OBJECT_TIP ), MakeTab ({ 3, 17}, STR_STRING_DEFINED_TOOLTIP ), // Copied object type times... - - kWidgetsEnd, }; // clang-format on @@ -1138,20 +1134,20 @@ namespace OpenRCT2::Ui::Windows } private: + bool tabWidgetsInitialised = false; + void InitWidgets() { - auto& targetWidgets = _window_editor_object_selection_widgets; - if (!_window_editor_object_selection_widgets_initialised) + SetWidgets(_window_editor_object_selection_widgets); + if (!tabWidgetsInitialised) { - _window_editor_object_selection_widgets_initialised = true; - auto tabWidget = targetWidgets[targetWidgets.size() - 2]; + tabWidgetsInitialised = true; + auto tabWidget = widgets[WIDX_TAB_1]; for (size_t i = 1; i < std::size(ObjectSelectionPages); i++) { - targetWidgets.insert(targetWidgets.end() - 1, tabWidget); + widgets.insert(widgets.end() - 1, tabWidget); } } - - widgets = targetWidgets.data(); } void SetPage(int32_t _page) diff --git a/src/openrct2-ui/windows/EditorObjectiveOptions.cpp b/src/openrct2-ui/windows/EditorObjectiveOptions.cpp index 050ff211fb..d920650264 100644 --- a/src/openrct2-ui/windows/EditorObjectiveOptions.cpp +++ b/src/openrct2-ui/windows/EditorObjectiveOptions.cpp @@ -117,7 +117,7 @@ namespace OpenRCT2::Ui::Windows MakeTab ({ 3, 17}, STR_SELECT_OBJECTIVE_AND_PARK_NAME_TIP ), \ MakeTab ({ 34, 17}, STR_SELECT_RIDES_TO_BE_PRESERVED_TIP ) - static Widget window_editor_objective_options_main_widgets[] = { + static constexpr Widget window_editor_objective_options_main_widgets[] = { MAIN_OBJECTIVE_OPTIONS_WIDGETS, MakeWidget ({ 98, 48}, {344, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary, STR_NONE, STR_SELECT_OBJECTIVE_FOR_THIS_SCENARIO_TIP ), MakeWidget ({430, 49}, { 11, 10}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH, STR_SELECT_OBJECTIVE_FOR_THIS_SCENARIO_TIP ), @@ -128,16 +128,14 @@ namespace OpenRCT2::Ui::Windows MakeWidget ({ 98, 133}, {180, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary, STR_NONE, STR_SELECT_WHICH_GROUP_THIS_SCENARIO_APPEARS_IN), MakeWidget ({266, 134}, { 11, 10}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH, STR_SELECT_WHICH_GROUP_THIS_SCENARIO_APPEARS_IN), MakeWidget ({370, 150}, { 75, 12}, WindowWidgetType::Button, WindowColour::Secondary, STR_CHANGE, STR_CHANGE_DETAIL_NOTES_ABOUT_PARK_SCENARIO_TIP), - kWidgetsEnd, }; - static Widget window_editor_objective_options_rides_widgets[] = { + static constexpr Widget window_editor_objective_options_rides_widgets[] = { MAIN_OBJECTIVE_OPTIONS_WIDGETS, MakeWidget({ 3, 60}, {374, 161}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_VERTICAL), - kWidgetsEnd, }; - static Widget *window_editor_objective_options_widgets[] = { + static constexpr std::span window_editor_objective_options_widgets[] = { window_editor_objective_options_main_widgets, window_editor_objective_options_rides_widgets, }; @@ -167,14 +165,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = window_editor_objective_options_main_widgets; - pressed_widgets = 0; - hold_down_widgets = window_editor_objective_options_page_hold_down_widgets - [WINDOW_EDITOR_OBJECTIVE_OPTIONS_PAGE_MAIN]; - InitScrollWidgets(); - selected_tab = WINDOW_EDITOR_OBJECTIVE_OPTIONS_PAGE_MAIN; - selected_list_item = -1; - UpdateDisabledWidgets(); + SetPage(WINDOW_EDITOR_OBJECTIVE_OPTIONS_PAGE_MAIN); } void OnMouseUp(WidgetIndex widgetIndex) override @@ -313,15 +304,12 @@ namespace OpenRCT2::Ui::Windows */ void SetPage(int32_t newPage) { - if (page == newPage) - return; - page = newPage; frame_no = 0; _rideableRides.clear(); selected_list_item = -1; hold_down_widgets = window_editor_objective_options_page_hold_down_widgets[newPage]; - widgets = window_editor_objective_options_widgets[newPage]; + SetWidgets(window_editor_objective_options_widgets[newPage]); Invalidate(); UpdateDisabledWidgets(); OnResize(); @@ -819,12 +807,6 @@ namespace OpenRCT2::Ui::Windows void OnPrepareDrawMain() { auto& gameState = GetGameState(); - auto widgetsToSet = window_editor_objective_options_widgets[page]; - if (widgets != widgetsToSet) - { - widgets = widgetsToSet; - InitScrollWidgets(); - } SetPressedTab(); @@ -832,12 +814,12 @@ namespace OpenRCT2::Ui::Windows { case OBJECTIVE_GUESTS_BY: case OBJECTIVE_PARK_VALUE_BY: - window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_1].type = WindowWidgetType::Spinner; - window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_1_INCREASE].type = WindowWidgetType::Button; - window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_1_DECREASE].type = WindowWidgetType::Button; - window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_2].type = WindowWidgetType::Spinner; - window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_2_INCREASE].type = WindowWidgetType::Button; - window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_2_DECREASE].type = WindowWidgetType::Button; + widgets[WIDX_OBJECTIVE_ARG_1].type = WindowWidgetType::Spinner; + widgets[WIDX_OBJECTIVE_ARG_1_INCREASE].type = WindowWidgetType::Button; + widgets[WIDX_OBJECTIVE_ARG_1_DECREASE].type = WindowWidgetType::Button; + widgets[WIDX_OBJECTIVE_ARG_2].type = WindowWidgetType::Spinner; + widgets[WIDX_OBJECTIVE_ARG_2_INCREASE].type = WindowWidgetType::Button; + widgets[WIDX_OBJECTIVE_ARG_2_DECREASE].type = WindowWidgetType::Button; break; case OBJECTIVE_GUESTS_AND_RATING: case OBJECTIVE_MONTHLY_RIDE_INCOME: @@ -845,26 +827,25 @@ namespace OpenRCT2::Ui::Windows case OBJECTIVE_FINISH_5_ROLLERCOASTERS: case OBJECTIVE_REPAY_LOAN_AND_PARK_VALUE: case OBJECTIVE_MONTHLY_FOOD_INCOME: - window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_1].type = WindowWidgetType::Spinner; - window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_1_INCREASE].type = WindowWidgetType::Button; - window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_1_DECREASE].type = WindowWidgetType::Button; - window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_2].type = WindowWidgetType::Empty; - window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_2_INCREASE].type = WindowWidgetType::Empty; - window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_2_DECREASE].type = WindowWidgetType::Empty; + widgets[WIDX_OBJECTIVE_ARG_1].type = WindowWidgetType::Spinner; + widgets[WIDX_OBJECTIVE_ARG_1_INCREASE].type = WindowWidgetType::Button; + widgets[WIDX_OBJECTIVE_ARG_1_DECREASE].type = WindowWidgetType::Button; + widgets[WIDX_OBJECTIVE_ARG_2].type = WindowWidgetType::Empty; + widgets[WIDX_OBJECTIVE_ARG_2_INCREASE].type = WindowWidgetType::Empty; + widgets[WIDX_OBJECTIVE_ARG_2_DECREASE].type = WindowWidgetType::Empty; break; default: - window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_1].type = WindowWidgetType::Empty; - window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_1_INCREASE].type = WindowWidgetType::Empty; - window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_1_DECREASE].type = WindowWidgetType::Empty; - window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_2].type = WindowWidgetType::Empty; - window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_2_INCREASE].type = WindowWidgetType::Empty; - window_editor_objective_options_main_widgets[WIDX_OBJECTIVE_ARG_2_DECREASE].type = WindowWidgetType::Empty; + widgets[WIDX_OBJECTIVE_ARG_1].type = WindowWidgetType::Empty; + widgets[WIDX_OBJECTIVE_ARG_1_INCREASE].type = WindowWidgetType::Empty; + widgets[WIDX_OBJECTIVE_ARG_1_DECREASE].type = WindowWidgetType::Empty; + widgets[WIDX_OBJECTIVE_ARG_2].type = WindowWidgetType::Empty; + widgets[WIDX_OBJECTIVE_ARG_2_INCREASE].type = WindowWidgetType::Empty; + widgets[WIDX_OBJECTIVE_ARG_2_DECREASE].type = WindowWidgetType::Empty; break; } - window_editor_objective_options_main_widgets[WIDX_CLOSE].type = (gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) - ? WindowWidgetType::Empty - : WindowWidgetType::CloseBox; + widgets[WIDX_CLOSE].type = (gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) ? WindowWidgetType::Empty + : WindowWidgetType::CloseBox; AnchorBorderWidgets(); } @@ -1110,18 +1091,10 @@ namespace OpenRCT2::Ui::Windows */ void OnPrepareDrawRides() { - Widget* widgetsToSet = window_editor_objective_options_widgets[page]; - if (widgets != widgetsToSet) - { - widgets = widgetsToSet; - InitScrollWidgets(); - } - SetPressedTab(); - window_editor_objective_options_main_widgets[WIDX_CLOSE].type = (gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) - ? WindowWidgetType::Empty - : WindowWidgetType::CloseBox; + widgets[WIDX_CLOSE].type = (gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) ? WindowWidgetType::Empty + : WindowWidgetType::CloseBox; AnchorBorderWidgets(); } diff --git a/src/openrct2-ui/windows/EditorParkEntrance.cpp b/src/openrct2-ui/windows/EditorParkEntrance.cpp index b316daccf9..90ef9fa509 100644 --- a/src/openrct2-ui/windows/EditorParkEntrance.cpp +++ b/src/openrct2-ui/windows/EditorParkEntrance.cpp @@ -63,7 +63,6 @@ namespace OpenRCT2::Ui::Windows MakeTab ({ 3, 17 }, STR_NONE ), MakeWidget ({ 2, 45 }, { kScrollWidth, kScrollHeight }, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_VERTICAL ), MakeWidget ({ kWindowWidth - 26, 59 }, { 24, 24 }, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_ROTATE_ARROW), STR_ROTATE_OBJECTS_90 ), - kWidgetsEnd, }; // clang-format on @@ -240,7 +239,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = _widgets; + SetWidgets(_widgets); InitScrollWidgets(); InitParkEntranceItems(); diff --git a/src/openrct2-ui/windows/EditorScenarioOptions.cpp b/src/openrct2-ui/windows/EditorScenarioOptions.cpp index b999ca04ef..e70fd52cec 100644 --- a/src/openrct2-ui/windows/EditorScenarioOptions.cpp +++ b/src/openrct2-ui/windows/EditorScenarioOptions.cpp @@ -123,7 +123,7 @@ namespace OpenRCT2::Ui::Windows }; // clang-format off - static Widget window_editor_scenario_options_financial_widgets[] = { + static constexpr Widget window_editor_scenario_options_financial_widgets[] = { WINDOW_SHIM(STR_SCENARIO_OPTIONS_FINANCIAL, WW_FINANCIAL, WH_FINANCIAL), MakeWidget ({ 0, 43}, { WW_FINANCIAL, 106}, WindowWidgetType::Resize, WindowColour::Secondary ), MakeTab ({ 3, 17}, STR_SCENARIO_OPTIONS_FINANCIAL_TIP), @@ -136,10 +136,9 @@ namespace OpenRCT2::Ui::Windows MakeSpinnerWidgets({168, 116}, { 70, 12}, WindowWidgetType::Spinner, WindowColour::Secondary ), // NB: 3 widgets MakeWidget ({ 8, 133}, {WW_FINANCIAL - 16, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_FORBID_MARKETING, STR_FORBID_MARKETING_TIP ), MakeWidget ({ 8, 116}, {WW_FINANCIAL - 16, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_RCT1_INTEREST, STR_RCT1_INTEREST_TIP ), - kWidgetsEnd, }; - static Widget window_editor_scenario_options_guests_widgets[] = { + static constexpr Widget window_editor_scenario_options_guests_widgets[] = { WINDOW_SHIM(STR_SCENARIO_OPTIONS_GUESTS, WW_GUESTS, WH_GUESTS), MakeWidget ({ 0, 43}, { WW_GUESTS, 106}, WindowWidgetType::Resize, WindowColour::Secondary), MakeRemapWidget ({ 3, 17}, { 31, 27}, WindowWidgetType::Tab, WindowColour::Secondary, SPR_TAB, STR_SCENARIO_OPTIONS_FINANCIAL_TIP ), @@ -151,10 +150,9 @@ namespace OpenRCT2::Ui::Windows MakeSpinnerWidgets({268, 99}, { 70, 12}, WindowWidgetType::Spinner, WindowColour::Secondary ), // NB: 3 widgets MakeWidget ({ 8, 116}, {WW_GUESTS - 16, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_GUESTS_PREFER_LESS_INTENSE_RIDES, STR_GUESTS_PREFER_LESS_INTENSE_RIDES_TIP), MakeWidget ({ 8, 133}, {WW_GUESTS - 16, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_GUESTS_PREFER_MORE_INTENSE_RIDES, STR_GUESTS_PREFER_MORE_INTENSE_RIDES_TIP), - kWidgetsEnd, }; - static Widget window_editor_scenario_options_park_widgets[] = { + static constexpr Widget window_editor_scenario_options_park_widgets[] = { WINDOW_SHIM(STR_SCENARIO_OPTIONS_PARK, WW_PARK, WH_PARK), MakeWidget ({ 0, 43}, { WW_PARK, 106}, WindowWidgetType::Resize, WindowColour::Secondary ), MakeRemapWidget ({ 3, 17}, { 31, 27}, WindowWidgetType::Tab, WindowColour::Secondary, SPR_TAB, STR_SCENARIO_OPTIONS_FINANCIAL_TIP), @@ -172,10 +170,9 @@ namespace OpenRCT2::Ui::Windows MakeWidget ({ 8, 150}, {WW_PARK - 16, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_FORBID_HIGH_CONSTRUCTION, STR_FORBID_HIGH_CONSTRUCTION_TIP ), MakeWidget ({ 8, 167}, {WW_PARK - 16, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_HARD_PARK_RATING, STR_HARD_PARK_RATING_TIP ), MakeWidget ({ 8, 184}, {WW_PARK - 16, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_HARD_GUEST_GENERATION, STR_HARD_GUEST_GENERATION_TIP ), - kWidgetsEnd, }; - static Widget *window_editor_scenario_options_widgets[] = { + static constexpr std::span window_editor_scenario_options_widgets[] = { window_editor_scenario_options_financial_widgets, window_editor_scenario_options_guests_widgets, window_editor_scenario_options_park_widgets, @@ -218,11 +215,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = window_editor_scenario_options_widgets[WINDOW_EDITOR_SCENARIO_OPTIONS_PAGE_FINANCIAL]; - hold_down_widgets = window_editor_scenario_options_page_hold_down_widgets - [WINDOW_EDITOR_SCENARIO_OPTIONS_PAGE_FINANCIAL]; - WindowInitScrollWidgets(*this); - page = 0; + SetPage(WINDOW_EDITOR_SCENARIO_OPTIONS_PAGE_FINANCIAL); } void OnMouseUp(WidgetIndex widgetIndex) override @@ -355,17 +348,14 @@ namespace OpenRCT2::Ui::Windows void SetPage(int32_t newPage) { - if (page == newPage) - return; - page = newPage; frame_no = 0; hold_down_widgets = window_editor_scenario_options_page_hold_down_widgets[page]; - widgets = window_editor_scenario_options_widgets[page]; + SetWidgets(window_editor_scenario_options_widgets[page]); Invalidate(); OnResize(); OnPrepareDraw(); - WindowInitScrollWidgets(*this); + InitScrollWidgets(); Invalidate(); } @@ -561,13 +551,6 @@ namespace OpenRCT2::Ui::Windows void FinancialPrepareDraw() { - Widget* newWidgets = window_editor_scenario_options_widgets[page]; - if (widgets != newWidgets) - { - widgets = newWidgets; - WindowInitScrollWidgets(*this); - } - SetPressedTab(); auto& gameState = GetGameState(); @@ -841,13 +824,6 @@ namespace OpenRCT2::Ui::Windows void GuestsPrepareDraw() { - Widget* newWidgets = window_editor_scenario_options_widgets[page]; - if (widgets != newWidgets) - { - widgets = newWidgets; - WindowInitScrollWidgets(*this); - } - SetPressedTab(); auto& gameState = GetGameState(); @@ -1147,13 +1123,6 @@ namespace OpenRCT2::Ui::Windows void ParkPrepareDraw() { - Widget* newWidgets = window_editor_scenario_options_widgets[page]; - if (widgets != newWidgets) - { - widgets = newWidgets; - WindowInitScrollWidgets(*this); - } - SetPressedTab(); auto& gameState = GetGameState(); diff --git a/src/openrct2-ui/windows/Error.cpp b/src/openrct2-ui/windows/Error.cpp index 4bc26497ac..47d8686099 100644 --- a/src/openrct2-ui/windows/Error.cpp +++ b/src/openrct2-ui/windows/Error.cpp @@ -30,9 +30,8 @@ namespace OpenRCT2::Ui::Windows static constexpr auto kMaxWidth = 250; static constexpr auto kPadding = 4; - static Widget window_error_widgets[] = { + static constexpr Widget window_error_widgets[] = { MakeWidget({ 0, 0 }, { 200, 42 }, WindowWidgetType::Frame, WindowColour::Primary), - kWidgetsEnd, }; class ErrorWindow final : public Window @@ -53,10 +52,11 @@ namespace OpenRCT2::Ui::Windows void OnOpen() override { - window_error_widgets[WIDX_BACKGROUND].right = width - 1; - window_error_widgets[WIDX_BACKGROUND].bottom = height - 1; + SetWidgets(window_error_widgets); + + widgets[WIDX_BACKGROUND].right = width - 1; + widgets[WIDX_BACKGROUND].bottom = height - 1; - widgets = window_error_widgets; _staleCount = 0; if (!gDisableErrorWindowSound) diff --git a/src/openrct2-ui/windows/Finances.cpp b/src/openrct2-ui/windows/Finances.cpp index 2e4eb431f6..045214ed34 100644 --- a/src/openrct2-ui/windows/Finances.cpp +++ b/src/openrct2-ui/windows/Finances.cpp @@ -108,33 +108,29 @@ namespace OpenRCT2::Ui::Windows MakeTab({ 127, 17 }, STR_FINANCES_SHOW_MARKETING_TAB_TIP), \ MakeTab({ 158, 17 }, STR_FINANCES_RESEARCH_TIP) - static Widget _windowFinancesSummaryWidgets[] = + static constexpr Widget _windowFinancesSummaryWidgets[] = { MAIN_FINANCES_WIDGETS(STR_FINANCIAL_SUMMARY, RSW_OTHER_TABS, RSH_SUMMARY, WW_OTHER_TABS, WH_SUMMARY), MakeWidget ({130, 50}, {391, 211}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_HORIZONTAL ), MakeSpinnerWidgets({ 64, 279}, { 97, 14}, WindowWidgetType::Spinner, WindowColour::Secondary, STR_FINANCES_SUMMARY_LOAN_VALUE), // NB: 3 widgets. - kWidgetsEnd, }; - static Widget _windowFinancesCashWidgets[] = + static constexpr Widget _windowFinancesCashWidgets[] = { MAIN_FINANCES_WIDGETS(STR_FINANCIAL_GRAPH, RSW_OTHER_TABS, RSH_OTHER_TABS, WW_OTHER_TABS, WH_OTHER_TABS), - kWidgetsEnd, }; - static Widget _windowFinancesParkValueWidgets[] = + static constexpr Widget _windowFinancesParkValueWidgets[] = { MAIN_FINANCES_WIDGETS(STR_PARK_VALUE_GRAPH, RSW_OTHER_TABS, RSH_OTHER_TABS, WW_OTHER_TABS, WH_OTHER_TABS), - kWidgetsEnd, }; - static Widget _windowFinancesProfitWidgets[] = + static constexpr Widget _windowFinancesProfitWidgets[] = { MAIN_FINANCES_WIDGETS(STR_PROFIT_GRAPH, RSW_OTHER_TABS, RSH_OTHER_TABS, WW_OTHER_TABS, WH_OTHER_TABS), - kWidgetsEnd, }; - static Widget _windowFinancesMarketingWidgets[] = + static constexpr Widget _windowFinancesMarketingWidgets[] = { MAIN_FINANCES_WIDGETS(STR_MARKETING, RSW_OTHER_TABS, RSH_OTHER_TABS, WW_OTHER_TABS, WH_OTHER_TABS), MakeWidget({3, 47}, { WW_OTHER_TABS - 6, 45}, WindowWidgetType::Groupbox, WindowColour::Tertiary , STR_MARKETING_CAMPAIGNS_IN_OPERATION ), @@ -145,10 +141,9 @@ namespace OpenRCT2::Ui::Windows MakeWidget({8, 0}, {WW_OTHER_TABS - 16, 14}, WindowWidgetType::ImgBtn, WindowColour::Secondary, 0xFFFFFFFF, STR_START_THIS_MARKETING_CAMPAIGN), MakeWidget({8, 0}, {WW_OTHER_TABS - 16, 14}, WindowWidgetType::ImgBtn, WindowColour::Secondary, 0xFFFFFFFF, STR_START_THIS_MARKETING_CAMPAIGN), MakeWidget({8, 0}, {WW_OTHER_TABS - 16, 14}, WindowWidgetType::ImgBtn, WindowColour::Secondary, 0xFFFFFFFF, STR_START_THIS_MARKETING_CAMPAIGN), - kWidgetsEnd, }; - static Widget _windowFinancesResearchWidgets[] = + static constexpr Widget _windowFinancesResearchWidgets[] = { MAIN_FINANCES_WIDGETS(STR_RESEARCH_FUNDING, RSW_RESEARCH, RSH_RESEARCH, WW_RESEARCH, WH_RESEARCH), MakeWidget({ 3, 47}, { WW_RESEARCH - 6, 45}, WindowWidgetType::Groupbox, WindowColour::Tertiary, STR_RESEARCH_FUNDING_ ), @@ -162,11 +157,10 @@ namespace OpenRCT2::Ui::Windows MakeWidget({ 8, 160}, {WW_RESEARCH - 14, 12}, WindowWidgetType::Checkbox, WindowColour::Tertiary, STR_RESEARCH_NEW_WATER_RIDES, STR_RESEARCH_NEW_WATER_RIDES_TIP ), MakeWidget({ 8, 173}, {WW_RESEARCH - 14, 12}, WindowWidgetType::Checkbox, WindowColour::Tertiary, STR_RESEARCH_NEW_SHOPS_AND_STALLS, STR_RESEARCH_NEW_SHOPS_AND_STALLS_TIP ), MakeWidget({ 8, 186}, {WW_RESEARCH - 14, 12}, WindowWidgetType::Checkbox, WindowColour::Tertiary, STR_RESEARCH_NEW_SCENERY_AND_THEMING, STR_RESEARCH_NEW_SCENERY_AND_THEMING_TIP ), - kWidgetsEnd, }; // clang-format on - static Widget* _windowFinancesPageWidgets[] = { + static constexpr std::span _windowFinancesPageWidgets[] = { _windowFinancesSummaryWidgets, // WINDOW_FINANCES_PAGE_SUMMARY _windowFinancesCashWidgets, // WINDOW_FINANCES_PAGE_FINANCIAL_GRAPH _windowFinancesParkValueWidgets, // WINDOW_FINANCES_PAGE_VALUE_GRAPH @@ -314,14 +308,6 @@ namespace OpenRCT2::Ui::Windows void OnPrepareDraw() override { - auto* targetWidgets = _windowFinancesPageWidgets[page]; - - if (widgets != targetWidgets) - { - widgets = targetWidgets; - WindowInitScrollWidgets(*this); - } - WindowAlignTabs(this, WIDX_TAB_1, WIDX_TAB_6); for (auto i = 0; i < WINDOW_FINANCES_PAGE_COUNT; i++) @@ -345,17 +331,17 @@ namespace OpenRCT2::Ui::Windows return; case WINDOW_FINANCES_PAGE_VALUE_GRAPH: - graphPageWidget = &_windowFinancesParkValueWidgets[WIDX_PAGE_BACKGROUND]; + graphPageWidget = &widgets[WIDX_PAGE_BACKGROUND]; centredGraph = false; _graphProps.series = GetGameState().Park.ValueHistory; break; case WINDOW_FINANCES_PAGE_PROFIT_GRAPH: - graphPageWidget = &_windowFinancesProfitWidgets[WIDX_PAGE_BACKGROUND]; + graphPageWidget = &widgets[WIDX_PAGE_BACKGROUND]; centredGraph = true; _graphProps.series = GetGameState().WeeklyProfitHistory; break; case WINDOW_FINANCES_PAGE_FINANCIAL_GRAPH: - graphPageWidget = &_windowFinancesCashWidgets[WIDX_PAGE_BACKGROUND]; + graphPageWidget = &widgets[WIDX_PAGE_BACKGROUND]; centredGraph = true; _graphProps.series = GetGameState().CashHistory; break; @@ -500,7 +486,7 @@ namespace OpenRCT2::Ui::Windows hold_down_widgets = _windowFinancesPageHoldDownWidgets[p]; pressed_widgets = 0; - widgets = _windowFinancesPageWidgets[p]; + SetWidgets(_windowFinancesPageWidgets[p]); SetDisabledTabs(); Invalidate(); @@ -533,8 +519,7 @@ namespace OpenRCT2::Ui::Windows } OnResize(); OnPrepareDraw(); - - WindowInitScrollWidgets(*this); + InitScrollWidgets(); // Scroll summary all the way to the right, initially. if (p == WINDOW_FINANCES_PAGE_SUMMARY) @@ -688,14 +673,14 @@ namespace OpenRCT2::Ui::Windows int32_t y = std::max(1, numActiveCampaigns) * kListRowHeight + 92; // Update group box positions - _windowFinancesMarketingWidgets[WIDX_ACTIVE_CAMPAIGNS_GROUP].bottom = y - 22; - _windowFinancesMarketingWidgets[WIDX_CAMPAIGNS_AVAILABLE_GROUP].top = y - 13; + widgets[WIDX_ACTIVE_CAMPAIGNS_GROUP].bottom = y - 22; + widgets[WIDX_CAMPAIGNS_AVAILABLE_GROUP].top = y - 13; // Update new campaign button visibility y += 3; for (int32_t i = 0; i < ADVERTISING_CAMPAIGN_COUNT; i++) { - auto campaignButton = &_windowFinancesMarketingWidgets[WIDX_CAMPAIGN_1 + i]; + auto campaignButton = &widgets[WIDX_CAMPAIGN_1 + i]; auto marketingCampaign = MarketingGetCampaign(i); if (marketingCampaign == nullptr && MarketingIsCampaignTypeApplicable(i)) { diff --git a/src/openrct2-ui/windows/Footpath.cpp b/src/openrct2-ui/windows/Footpath.cpp index 1161868fd8..05e5a3f302 100644 --- a/src/openrct2-ui/windows/Footpath.cpp +++ b/src/openrct2-ui/windows/Footpath.cpp @@ -124,7 +124,7 @@ namespace OpenRCT2::Ui::Windows }; // clang-format off - static Widget window_footpath_widgets[] = { + static constexpr Widget window_footpath_widgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW_WINDOW, WH_WINDOW), // Type group @@ -152,7 +152,6 @@ namespace OpenRCT2::Ui::Windows MakeWidget({ 3, 361}, {100, 54}, WindowWidgetType::Groupbox, WindowColour::Primary ), MakeWidget({13, 372}, { 36, 36}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_CONSTRUCTION_FOOTPATH_LAND), STR_CONSTRUCT_FOOTPATH_ON_LAND_TIP ), MakeWidget({57, 372}, { 36, 36}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_CONSTRUCTION_FOOTPATH_BRIDGE), STR_CONSTRUCT_BRIDGE_OR_TUNNEL_FOOTPATH_TIP ), - kWidgetsEnd, }; #pragma endregion @@ -215,7 +214,7 @@ namespace OpenRCT2::Ui::Windows void OnOpen() override { - widgets = window_footpath_widgets; + SetWidgets(window_footpath_widgets); WindowInitScrollWidgets(*this); WindowPushOthersRight(*this); @@ -275,13 +274,13 @@ namespace OpenRCT2::Ui::Windows switch (widgetIndex) { case WIDX_FOOTPATH_TYPE: - WindowFootpathShowFootpathTypesDialog(&window_footpath_widgets[widgetIndex], false); + WindowFootpathShowFootpathTypesDialog(&widgets[widgetIndex], false); break; case WIDX_QUEUELINE_TYPE: - WindowFootpathShowFootpathTypesDialog(&window_footpath_widgets[widgetIndex], true); + WindowFootpathShowFootpathTypesDialog(&widgets[widgetIndex], true); break; case WIDX_RAILINGS_TYPE: - WindowFootpathShowRailingsTypesDialog(&window_footpath_widgets[widgetIndex]); + WindowFootpathShowRailingsTypesDialog(&widgets[widgetIndex]); break; case WIDX_DIRECTION_NW: WindowFootpathMousedownDirection(0); @@ -452,17 +451,17 @@ namespace OpenRCT2::Ui::Windows : (1uLL << WIDX_FOOTPATH_TYPE); // Enable / disable construct button - window_footpath_widgets[WIDX_CONSTRUCT].type = _footpathConstructionMode == PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL + widgets[WIDX_CONSTRUCT].type = _footpathConstructionMode == PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL ? WindowWidgetType::ImgBtn : WindowWidgetType::Empty; if (gFootpathSelection.LegacyPath == OBJECT_ENTRY_INDEX_NULL) { - window_footpath_widgets[WIDX_RAILINGS_TYPE].type = WindowWidgetType::FlatBtn; + widgets[WIDX_RAILINGS_TYPE].type = WindowWidgetType::FlatBtn; } else { - window_footpath_widgets[WIDX_RAILINGS_TYPE].type = WindowWidgetType::Empty; + widgets[WIDX_RAILINGS_TYPE].type = WindowWidgetType::Empty; } } @@ -517,22 +516,19 @@ namespace OpenRCT2::Ui::Windows // Draw construction image screenCoords = this->windowPos - + ScreenCoordsXY{ window_footpath_widgets[WIDX_CONSTRUCT].midX(), - window_footpath_widgets[WIDX_CONSTRUCT].bottom - 60 }; + + ScreenCoordsXY{ widgets[WIDX_CONSTRUCT].midX(), widgets[WIDX_CONSTRUCT].bottom - 60 }; GfxDrawSprite(dpi, ImageId(image), screenCoords); } // Draw build this... label screenCoords = this->windowPos - + ScreenCoordsXY{ window_footpath_widgets[WIDX_CONSTRUCT].midX(), - window_footpath_widgets[WIDX_CONSTRUCT].bottom - 23 }; + + ScreenCoordsXY{ widgets[WIDX_CONSTRUCT].midX(), widgets[WIDX_CONSTRUCT].bottom - 23 }; DrawTextBasic(dpi, screenCoords, STR_BUILD_THIS, {}, { TextAlignment::CENTRE }); } // Draw cost screenCoords = this->windowPos - + ScreenCoordsXY{ window_footpath_widgets[WIDX_CONSTRUCT].midX(), - window_footpath_widgets[WIDX_CONSTRUCT].bottom - 12 }; + + ScreenCoordsXY{ widgets[WIDX_CONSTRUCT].midX(), widgets[WIDX_CONSTRUCT].bottom - 12 }; if (_windowFootpathCost != kMoney64Undefined) { if (!(GetGameState().Park.Flags & PARK_FLAGS_NO_MONEY)) diff --git a/src/openrct2-ui/windows/GameBottomToolbar.cpp b/src/openrct2-ui/windows/GameBottomToolbar.cpp index 495ad09782..636c64f942 100644 --- a/src/openrct2-ui/windows/GameBottomToolbar.cpp +++ b/src/openrct2-ui/windows/GameBottomToolbar.cpp @@ -52,7 +52,7 @@ namespace OpenRCT2::Ui::Windows }; // clang-format off - static Widget window_game_bottom_toolbar_widgets[] = + static constexpr Widget window_game_bottom_toolbar_widgets[] = { MakeWidget({ 0, 0}, {142, 34}, WindowWidgetType::ImgBtn, WindowColour::Primary ), // Left outset panel MakeWidget({ 2, 2}, {138, 30}, WindowWidgetType::ImgBtn, WindowColour::Primary ), // Left inset panel @@ -68,7 +68,6 @@ namespace OpenRCT2::Ui::Windows MakeWidget({498, 0}, {142, 34}, WindowWidgetType::ImgBtn, WindowColour::Primary ), // Right outset panel MakeWidget({500, 2}, {138, 30}, WindowWidgetType::ImgBtn, WindowColour::Primary ), // Right inset panel MakeWidget({500, 2}, {138, 12}, WindowWidgetType::FlatBtn, WindowColour::Primary ), // Date - kWidgetsEnd, }; // clang-format on @@ -87,12 +86,10 @@ namespace OpenRCT2::Ui::Windows void DrawLeftPanel(DrawPixelInfo& dpi) { - const auto topLeft = windowPos - + ScreenCoordsXY{ window_game_bottom_toolbar_widgets[WIDX_LEFT_OUTSET].left + 1, - window_game_bottom_toolbar_widgets[WIDX_LEFT_OUTSET].top + 1 }; - const auto bottomRight = windowPos - + ScreenCoordsXY{ window_game_bottom_toolbar_widgets[WIDX_LEFT_OUTSET].right - 1, - window_game_bottom_toolbar_widgets[WIDX_LEFT_OUTSET].bottom - 1 }; + const auto& leftPanelWidget = widgets[WIDX_LEFT_OUTSET]; + + const auto topLeft = windowPos + ScreenCoordsXY{ leftPanelWidget.left + 1, leftPanelWidget.top + 1 }; + const auto bottomRight = windowPos + ScreenCoordsXY{ leftPanelWidget.right - 1, leftPanelWidget.bottom - 1 }; // Draw green inset rectangle on panel GfxFillRectInset(dpi, { topLeft, bottomRight }, colours[1], INSET_RECT_F_30); @@ -104,7 +101,7 @@ namespace OpenRCT2::Ui::Windows // Draw money if (!(gameState.Park.Flags & PARK_FLAGS_NO_MONEY)) { - Widget widget = window_game_bottom_toolbar_widgets[WIDX_MONEY]; + const auto& widget = widgets[WIDX_MONEY]; auto screenCoords = ScreenCoordsXY{ windowPos.x + widget.midX(), windowPos.y + widget.midY() - (line_height == 10 ? 5 : 6) }; @@ -129,7 +126,7 @@ namespace OpenRCT2::Ui::Windows // Draw guests { - Widget widget = window_game_bottom_toolbar_widgets[WIDX_GUESTS]; + const auto& widget = widgets[WIDX_GUESTS]; auto screenCoords = ScreenCoordsXY{ windowPos.x + widget.midX(), windowPos.y + widget.midY() - 6 }; StringId stringId = gameState.NumGuestsInPark == 1 ? _guestCountFormatsSingular[gameState.GuestChangeModifier] @@ -142,7 +139,7 @@ namespace OpenRCT2::Ui::Windows // Draw park rating { - Widget widget = window_game_bottom_toolbar_widgets[WIDX_PARK_RATING]; + const auto& widget = widgets[WIDX_PARK_RATING]; auto screenCoords = windowPos + ScreenCoordsXY{ widget.left + 11, widget.midY() - 5 }; DrawParkRating(dpi, colours[3].colour, screenCoords, std::max(10, ((gameState.Park.Rating / 4) * 263) / 256)); @@ -171,20 +168,15 @@ namespace OpenRCT2::Ui::Windows void DrawRightPanel(DrawPixelInfo& dpi) { - const auto topLeft = windowPos - + ScreenCoordsXY{ window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].left + 1, - window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].top + 1 }; - const auto bottomRight = windowPos - + ScreenCoordsXY{ window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].right - 1, - window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].bottom - 1 }; + const auto& rightPanelWidget = widgets[WIDX_RIGHT_OUTSET]; + + const auto topLeft = windowPos + ScreenCoordsXY{ rightPanelWidget.left + 1, rightPanelWidget.top + 1 }; + const auto bottomRight = windowPos + ScreenCoordsXY{ rightPanelWidget.right - 1, rightPanelWidget.bottom - 1 }; // Draw green inset rectangle on panel GfxFillRectInset(dpi, { topLeft, bottomRight }, colours[1], INSET_RECT_F_30); - auto screenCoords = ScreenCoordsXY{ (window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].left - + window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].right) - / 2 - + windowPos.x, - window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].top + windowPos.y + 2 }; + auto screenCoords = ScreenCoordsXY{ (rightPanelWidget.left + rightPanelWidget.right) / 2 + windowPos.x, + rightPanelWidget.top + windowPos.y + 2 }; // Date auto& date = GetDate(); @@ -204,8 +196,7 @@ namespace OpenRCT2::Ui::Windows uint32_t line_height = FontGetLineHeight(FontStyle::Medium); // Temperature - screenCoords = { windowPos.x + window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].left + 15, - static_cast(screenCoords.y + line_height + 1) }; + screenCoords = { windowPos.x + rightPanelWidget.left + 15, static_cast(screenCoords.y + line_height + 1) }; int32_t temperature = GetGameState().ClimateCurrent.Temperature; StringId format = STR_CELSIUS_VALUE; @@ -237,27 +228,26 @@ namespace OpenRCT2::Ui::Windows void DrawNewsItem(DrawPixelInfo& dpi) { - auto* middleOutsetWidget = &window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET]; + const auto& middleOutsetWidget = widgets[WIDX_MIDDLE_OUTSET]; auto* newsItem = News::GetItem(0); // Current news item GfxFillRectInset( dpi, - { windowPos + ScreenCoordsXY{ middleOutsetWidget->left + 1, middleOutsetWidget->top + 1 }, - windowPos + ScreenCoordsXY{ middleOutsetWidget->right - 1, middleOutsetWidget->bottom - 1 } }, + { windowPos + ScreenCoordsXY{ middleOutsetWidget.left + 1, middleOutsetWidget.top + 1 }, + windowPos + ScreenCoordsXY{ middleOutsetWidget.right - 1, middleOutsetWidget.bottom - 1 } }, colours[2], INSET_RECT_F_30); // Text - auto screenCoords = windowPos + ScreenCoordsXY{ middleOutsetWidget->midX(), middleOutsetWidget->top + 11 }; - int32_t itemWidth = middleOutsetWidget->width() - 62; + auto screenCoords = windowPos + ScreenCoordsXY{ middleOutsetWidget.midX(), middleOutsetWidget.top + 11 }; + int32_t itemWidth = middleOutsetWidget.width() - 62; DrawNewsTicker( dpi, screenCoords, itemWidth, COLOUR_BRIGHT_GREEN, STR_BOTTOM_TOOLBAR_NEWS_TEXT, newsItem->Text, newsItem->Ticks); - screenCoords = windowPos - + ScreenCoordsXY{ window_game_bottom_toolbar_widgets[WIDX_NEWS_SUBJECT].left, - window_game_bottom_toolbar_widgets[WIDX_NEWS_SUBJECT].top }; + const auto& newsSubjectWidget = widgets[WIDX_NEWS_SUBJECT]; + screenCoords = windowPos + ScreenCoordsXY{ newsSubjectWidget.left, newsSubjectWidget.top }; switch (newsItem->Type) { case News::ItemType::Ride: @@ -342,7 +332,7 @@ namespace OpenRCT2::Ui::Windows void DrawMiddlePanel(DrawPixelInfo& dpi) { - Widget* middleOutsetWidget = &window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET]; + Widget* middleOutsetWidget = &widgets[WIDX_MIDDLE_OUTSET]; GfxFillRectInset( dpi, @@ -411,14 +401,14 @@ namespace OpenRCT2::Ui::Windows public: GameBottomToolbar() { - widgets = window_game_bottom_toolbar_widgets; + SetWidgets(window_game_bottom_toolbar_widgets); frame_no = 0; InitScrollWidgets(); // Reset the middle widget to not show by default. // If it is required to be shown news_update will reshow it. - window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].type = WindowWidgetType::Empty; + widgets[WIDX_MIDDLE_OUTSET].type = WindowWidgetType::Empty; } void OnMouseUp(WidgetIndex widgetIndex) override @@ -536,56 +526,55 @@ namespace OpenRCT2::Ui::Windows int32_t x = ContextGetWidth(); width = x; x--; - window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].right = x; + widgets[WIDX_RIGHT_OUTSET].right = x; x -= 2; - window_game_bottom_toolbar_widgets[WIDX_RIGHT_INSET].right = x; + widgets[WIDX_RIGHT_INSET].right = x; x -= 137; - window_game_bottom_toolbar_widgets[WIDX_RIGHT_INSET].left = x; + widgets[WIDX_RIGHT_INSET].left = x; x -= 2; - window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].left = x; + widgets[WIDX_RIGHT_OUTSET].left = x; x--; - window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].right = x; + widgets[WIDX_MIDDLE_OUTSET].right = x; x -= 2; - window_game_bottom_toolbar_widgets[WIDX_MIDDLE_INSET].right = x; + widgets[WIDX_MIDDLE_INSET].right = x; x -= 3; - window_game_bottom_toolbar_widgets[WIDX_NEWS_LOCATE].right = x; + widgets[WIDX_NEWS_LOCATE].right = x; x -= 23; - window_game_bottom_toolbar_widgets[WIDX_NEWS_LOCATE].left = x; - window_game_bottom_toolbar_widgets[WIDX_DATE].left = window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].left + 2; - window_game_bottom_toolbar_widgets[WIDX_DATE].right = window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].right - - 2; + widgets[WIDX_NEWS_LOCATE].left = x; + widgets[WIDX_DATE].left = widgets[WIDX_RIGHT_OUTSET].left + 2; + widgets[WIDX_DATE].right = widgets[WIDX_RIGHT_OUTSET].right - 2; - window_game_bottom_toolbar_widgets[WIDX_LEFT_INSET].type = WindowWidgetType::Empty; - window_game_bottom_toolbar_widgets[WIDX_RIGHT_INSET].type = WindowWidgetType::Empty; + widgets[WIDX_LEFT_INSET].type = WindowWidgetType::Empty; + widgets[WIDX_RIGHT_INSET].type = WindowWidgetType::Empty; if (News::IsQueueEmpty()) { if (!(ThemeGetFlags() & UITHEME_FLAG_USE_FULL_BOTTOM_TOOLBAR)) { - window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].type = WindowWidgetType::Empty; - window_game_bottom_toolbar_widgets[WIDX_MIDDLE_INSET].type = WindowWidgetType::Empty; - window_game_bottom_toolbar_widgets[WIDX_NEWS_SUBJECT].type = WindowWidgetType::Empty; - window_game_bottom_toolbar_widgets[WIDX_NEWS_LOCATE].type = WindowWidgetType::Empty; + widgets[WIDX_MIDDLE_OUTSET].type = WindowWidgetType::Empty; + widgets[WIDX_MIDDLE_INSET].type = WindowWidgetType::Empty; + widgets[WIDX_NEWS_SUBJECT].type = WindowWidgetType::Empty; + widgets[WIDX_NEWS_LOCATE].type = WindowWidgetType::Empty; } else { - window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].type = WindowWidgetType::ImgBtn; - window_game_bottom_toolbar_widgets[WIDX_MIDDLE_INSET].type = WindowWidgetType::FlatBtn; - window_game_bottom_toolbar_widgets[WIDX_NEWS_SUBJECT].type = WindowWidgetType::Empty; - window_game_bottom_toolbar_widgets[WIDX_NEWS_LOCATE].type = WindowWidgetType::Empty; - window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].colour = 0; - window_game_bottom_toolbar_widgets[WIDX_MIDDLE_INSET].colour = 0; + widgets[WIDX_MIDDLE_OUTSET].type = WindowWidgetType::ImgBtn; + widgets[WIDX_MIDDLE_INSET].type = WindowWidgetType::FlatBtn; + widgets[WIDX_NEWS_SUBJECT].type = WindowWidgetType::Empty; + widgets[WIDX_NEWS_LOCATE].type = WindowWidgetType::Empty; + widgets[WIDX_MIDDLE_OUTSET].colour = 0; + widgets[WIDX_MIDDLE_INSET].colour = 0; } } else { News::Item* newsItem = News::GetItem(0); - window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].type = WindowWidgetType::ImgBtn; - window_game_bottom_toolbar_widgets[WIDX_MIDDLE_INSET].type = WindowWidgetType::FlatBtn; - window_game_bottom_toolbar_widgets[WIDX_NEWS_SUBJECT].type = WindowWidgetType::FlatBtn; - window_game_bottom_toolbar_widgets[WIDX_NEWS_LOCATE].type = WindowWidgetType::FlatBtn; - window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].colour = 2; - window_game_bottom_toolbar_widgets[WIDX_MIDDLE_INSET].colour = 2; + widgets[WIDX_MIDDLE_OUTSET].type = WindowWidgetType::ImgBtn; + widgets[WIDX_MIDDLE_INSET].type = WindowWidgetType::FlatBtn; + widgets[WIDX_NEWS_SUBJECT].type = WindowWidgetType::FlatBtn; + widgets[WIDX_NEWS_LOCATE].type = WindowWidgetType::FlatBtn; + widgets[WIDX_MIDDLE_OUTSET].colour = 2; + widgets[WIDX_MIDDLE_INSET].colour = 2; disabled_widgets &= ~(1uLL << WIDX_NEWS_SUBJECT); disabled_widgets &= ~(1uLL << WIDX_NEWS_LOCATE); @@ -598,7 +587,7 @@ namespace OpenRCT2::Ui::Windows if (!(newsItem->TypeHasSubject())) { disabled_widgets |= (1uLL << WIDX_NEWS_SUBJECT); - window_game_bottom_toolbar_widgets[WIDX_NEWS_SUBJECT].type = WindowWidgetType::Empty; + widgets[WIDX_NEWS_SUBJECT].type = WindowWidgetType::Empty; } if (newsItem->HasButton()) @@ -611,9 +600,9 @@ namespace OpenRCT2::Ui::Windows void OnDraw(DrawPixelInfo& dpi) override { - auto leftWidget = window_game_bottom_toolbar_widgets[WIDX_LEFT_OUTSET]; - auto rightWidget = window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET]; - auto middleWidget = window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET]; + auto leftWidget = widgets[WIDX_LEFT_OUTSET]; + auto rightWidget = widgets[WIDX_RIGHT_OUTSET]; + auto middleWidget = widgets[WIDX_MIDDLE_OUTSET]; // Draw panel grey backgrounds auto leftTop = windowPos + ScreenCoordsXY{ leftWidget.left, leftWidget.top }; diff --git a/src/openrct2-ui/windows/Guest.cpp b/src/openrct2-ui/windows/Guest.cpp index 6630332beb..fb8372231d 100644 --- a/src/openrct2-ui/windows/Guest.cpp +++ b/src/openrct2-ui/windows/Guest.cpp @@ -113,7 +113,7 @@ namespace OpenRCT2::Ui::Windows MakeTab({ 189, 17 }, STR_DEBUG_TIP) /* Tab 7 */ // clang-format off - static Widget _guestWindowWidgetsOverview[] = { + static constexpr Widget _guestWindowWidgetsOverview[] = { MAIN_GUEST_WIDGETS, MakeWidget({ 3, 45}, {164, 12}, WindowWidgetType::LabelCentred, WindowColour::Secondary ), // Label Thought marquee MakeWidget({ 3, 57}, {164, 87}, WindowWidgetType::Viewport, WindowColour::Secondary ), // Viewport @@ -122,11 +122,10 @@ namespace OpenRCT2::Ui::Windows MakeWidget({167, 69}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_RENAME), STR_NAME_GUEST_TIP ), // Rename Button MakeWidget({167, 93}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_LOCATE), STR_LOCATE_SUBJECT_TIP ), // Locate Button MakeWidget({167, 117}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_TRACK_PEEP), STR_TOGGLE_GUEST_TRACKING_TIP), // Track Button - kWidgetsEnd, }; // clang-format on - static Widget _guestWindowWidgetsStats[] = { + static constexpr Widget _guestWindowWidgetsStats[] = { MAIN_GUEST_WIDGETS, MakeProgressBar({ 65, (kListRowHeight * 0) + 4 + 43 }, { 119, 10 }, COLOUR_BRIGHT_GREEN, 0, 19), // Happiness MakeProgressBar({ 65, (kListRowHeight * 1) + 4 + 43 }, { 119, 10 }, COLOUR_BRIGHT_GREEN, 0, 19), // Energy @@ -134,37 +133,31 @@ namespace OpenRCT2::Ui::Windows MakeProgressBar({ 65, (kListRowHeight * 3) + 4 + 43 }, { 119, 10 }, COLOUR_BRIGHT_RED, 67, 100), // Thirst MakeProgressBar({ 65, (kListRowHeight * 4) + 4 + 43 }, { 119, 10 }, COLOUR_BRIGHT_RED, 47, 100), // Nausea MakeProgressBar({ 65, (kListRowHeight * 5) + 4 + 43 }, { 119, 10 }, COLOUR_BRIGHT_RED, 62, 100), // Toilet - kWidgetsEnd, }; - static Widget _guestWindowWidgetsRides[] = { + static constexpr Widget _guestWindowWidgetsRides[] = { MAIN_GUEST_WIDGETS, MakeWidget({ 3, 57 }, { 186, 87 }, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_VERTICAL), - kWidgetsEnd, }; - static Widget _guestWindowWidgetsFinance[] = { + static constexpr Widget _guestWindowWidgetsFinance[] = { MAIN_GUEST_WIDGETS, - kWidgetsEnd, }; - static Widget _guestWindowWidgetsThoughts[] = { + static constexpr Widget _guestWindowWidgetsThoughts[] = { MAIN_GUEST_WIDGETS, - kWidgetsEnd, }; - static Widget _guestWindowWidgetsInventory[] = { + static constexpr Widget _guestWindowWidgetsInventory[] = { MAIN_GUEST_WIDGETS, - kWidgetsEnd, }; - static Widget _guestWindowWidgetsDebug[] = { + static constexpr Widget _guestWindowWidgetsDebug[] = { MAIN_GUEST_WIDGETS, - kWidgetsEnd, }; // clang-format off - static constexpr std::array _guestWindowPageWidgets = { + static constexpr std::span _guestWindowPageWidgets[] = { _guestWindowWidgetsOverview, _guestWindowWidgetsStats, _guestWindowWidgetsRides, @@ -173,7 +166,7 @@ namespace OpenRCT2::Ui::Windows _guestWindowWidgetsInventory, _guestWindowWidgetsDebug, }; - static_assert(_guestWindowPageWidgets.size() == WINDOW_GUEST_PAGE_COUNT); + static_assert(std::size(_guestWindowPageWidgets) == WINDOW_GUEST_PAGE_COUNT); // clang-format on static constexpr std::array _guestWindowPageSizes = { @@ -199,7 +192,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = _guestWindowWidgetsOverview; + SetWidgets(_guestWindowWidgetsOverview); page = WINDOW_GUEST_OVERVIEW; frame_no = 0; _marqueePosition = 0; @@ -448,12 +441,6 @@ namespace OpenRCT2::Ui::Windows void OnPrepareDrawCommon() { - if (_guestWindowPageWidgets[page] != widgets) - { - widgets = _guestWindowPageWidgets[page]; - InitScrollWidgets(); - } - pressed_widgets |= 1uLL << (page + WIDX_TAB_1); const auto peep = GetGuest(); @@ -521,7 +508,7 @@ namespace OpenRCT2::Ui::Windows hold_down_widgets = 0; pressed_widgets = 0; - widgets = _guestWindowPageWidgets[page]; + SetWidgets(_guestWindowPageWidgets[page]); DisableWidgets(); Invalidate(); OnResize(); diff --git a/src/openrct2-ui/windows/GuestList.cpp b/src/openrct2-ui/windows/GuestList.cpp index 3fc9fe28dd..353e5037c1 100644 --- a/src/openrct2-ui/windows/GuestList.cpp +++ b/src/openrct2-ui/windows/GuestList.cpp @@ -58,7 +58,7 @@ namespace OpenRCT2::Ui::Windows }; // clang-format off - static Widget window_guest_list_widgets[] = { + static constexpr Widget window_guest_list_widgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), MakeWidget({ 0, 43}, {350, 287}, WindowWidgetType::Resize, WindowColour::Secondary ), // tab content panel MakeWidget({ 5, 59}, { 80, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary, STR_ARG_4_PAGE_X ), // page dropdown @@ -71,7 +71,6 @@ namespace OpenRCT2::Ui::Windows MakeTab ({ 3, 17}, STR_INDIVIDUAL_GUESTS_TIP ), // tab 1 MakeTab ({ 34, 17}, STR_SUMMARISED_GUESTS_TIP ), // tab 2 MakeWidget({ 3, 72}, {344, 255}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_BOTH ), // guest list - kWidgetsEnd, }; // clang-format on @@ -161,7 +160,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = window_guest_list_widgets; + SetWidgets(window_guest_list_widgets); WindowInitScrollWidgets(*this); _selectedTab = TabId::Summarised; diff --git a/src/openrct2-ui/windows/InstallTrack.cpp b/src/openrct2-ui/windows/InstallTrack.cpp index 982a3f8533..fd3aa0eda0 100644 --- a/src/openrct2-ui/windows/InstallTrack.cpp +++ b/src/openrct2-ui/windows/InstallTrack.cpp @@ -50,14 +50,13 @@ namespace OpenRCT2::Ui::Windows constexpr int32_t ACTION_BUTTONS_LEFT = WW - 100; // clang-format off - static Widget window_install_track_widgets[] = { + static constexpr Widget window_install_track_widgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), MakeWidget({ 4, 18}, {372, 219}, WindowWidgetType::FlatBtn, WindowColour::Primary ), MakeWidget({PREVIEW_BUTTONS_LEFT, 422}, { 22, 24}, WindowWidgetType::FlatBtn, WindowColour::Primary, ImageId(SPR_ROTATE_ARROW), STR_ROTATE_90_TIP ), MakeWidget({PREVIEW_BUTTONS_LEFT, 398}, { 22, 24}, WindowWidgetType::FlatBtn, WindowColour::Primary, ImageId(SPR_SCENERY), STR_TOGGLE_SCENERY_TIP), MakeWidget({ ACTION_BUTTONS_LEFT, 241}, { 97, 15}, WindowWidgetType::Button, WindowColour::Primary, STR_INSTALL_NEW_TRACK_DESIGN_INSTALL ), MakeWidget({ ACTION_BUTTONS_LEFT, 259}, { 97, 15}, WindowWidgetType::Button, WindowColour::Primary, STR_INSTALL_NEW_TRACK_DESIGN_CANCEL ), - kWidgetsEnd, }; // clang-format on @@ -83,7 +82,7 @@ namespace OpenRCT2::Ui::Windows void OnOpen() override { - widgets = window_install_track_widgets; + SetWidgets(window_install_track_widgets); WindowInitScrollWidgets(*this); WindowPushOthersRight(*this); @@ -152,7 +151,7 @@ namespace OpenRCT2::Ui::Windows DrawWidgets(dpi); // Track preview - Widget* widget = &window_install_track_widgets[WIDX_TRACK_PREVIEW]; + Widget* widget = &widgets[WIDX_TRACK_PREVIEW]; auto screenPos = windowPos + ScreenCoordsXY{ widget->left + 1, widget->top + 1 }; int32_t colour = ColourMapA[colours[0].colour].darkest; GfxFillRect(dpi, { screenPos, screenPos + ScreenCoordsXY{ 369, 216 } }, colour); diff --git a/src/openrct2-ui/windows/Land.cpp b/src/openrct2-ui/windows/Land.cpp index c45cb33206..077ba3569c 100644 --- a/src/openrct2-ui/windows/Land.cpp +++ b/src/openrct2-ui/windows/Land.cpp @@ -53,7 +53,7 @@ namespace OpenRCT2::Ui::Windows }; // clang-format off - static Widget window_land_widgets[] = { + static constexpr Widget window_land_widgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), MakeWidget ({19, 19}, {24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_RIDE_CONSTRUCTION_SLOPE_UP), STR_ENABLE_MOUNTAIN_TOOL_TIP), // mountain mode MakeWidget ({55, 19}, {24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_PAINTBRUSH), STR_DISABLE_ELEVATION), // paint mode @@ -62,7 +62,6 @@ namespace OpenRCT2::Ui::Windows MakeRemapWidget({54, 63}, {16, 16}, WindowWidgetType::TrnBtn, WindowColour::Secondary, SPR_LAND_TOOL_INCREASE, STR_ADJUST_LARGER_LAND_TIP), // increment size MakeWidget ({ 2, 106}, {47, 36}, WindowWidgetType::FlatBtn, WindowColour::Secondary, 0xFFFFFFFF, STR_CHANGE_BASE_LAND_TIP), // floor texture MakeWidget ({49, 106}, {47, 36}, WindowWidgetType::FlatBtn, WindowColour::Secondary, 0xFFFFFFFF, STR_CHANGE_VERTICAL_LAND_TIP), // wall texture - kWidgetsEnd, }; // clang-format on @@ -90,7 +89,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = window_land_widgets; + SetWidgets(window_land_widgets); hold_down_widgets = (1uLL << WIDX_DECREMENT) | (1uLL << WIDX_INCREMENT); WindowInitScrollWidgets(*this); WindowPushOthersBelow(*this); @@ -407,7 +406,7 @@ namespace OpenRCT2::Ui::Windows return; WidgetIndex widget_index = windowMgr->FindWidgetFromPoint(*window, screenPos); - if (widget_index == -1) + if (widget_index == kWidgetIndexNull) return; const auto& widget = window->widgets[widget_index]; diff --git a/src/openrct2-ui/windows/LandRights.cpp b/src/openrct2-ui/windows/LandRights.cpp index a7ef2463ba..157835ec2e 100644 --- a/src/openrct2-ui/windows/LandRights.cpp +++ b/src/openrct2-ui/windows/LandRights.cpp @@ -57,7 +57,7 @@ namespace OpenRCT2::Ui::Windows }; // clang-format off - static Widget window_land_rights_widgets[] = { + static constexpr Widget window_land_rights_widgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), MakeWidget ({ 27, 17}, { 44, 32}, WindowWidgetType::ImgBtn, WindowColour::Primary, ImageId(SPR_LAND_TOOL_SIZE_0) ), // preview box MakeRemapWidget({ 28, 18}, { 16, 16}, WindowWidgetType::TrnBtn, WindowColour::Primary, SPR_LAND_TOOL_DECREASE, STR_ADJUST_SMALLER_LAND_RIGHTS_TIP ), // decrement size @@ -69,7 +69,6 @@ namespace OpenRCT2::Ui::Windows MakeWidget ({100, 54}, {170, 12}, WindowWidgetType::Empty, WindowColour::Primary, STR_LAND_OWNED, STR_SET_LAND_TO_BE_OWNED_TIP ), MakeWidget ({100, 70}, {170, 12}, WindowWidgetType::Empty, WindowColour::Primary, STR_CONSTRUCTION_RIGHTS_SALE, STR_SET_CONSTRUCTION_RIGHTS_TO_BE_AVAILABLE_TIP), MakeWidget ({100, 86}, {170, 12}, WindowWidgetType::Empty, WindowColour::Primary, STR_CONSTRUCTION_RIGHTS_OWNED, STR_SET_CONSTRUCTION_RIGHTS_TO_BE_OWNED_TIP ), - kWidgetsEnd, }; // clang-format on @@ -126,7 +125,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = window_land_rights_widgets; + SetWidgets(window_land_rights_widgets); hold_down_widgets = (1uLL << WIDX_INCREMENT) | (1uLL << WIDX_DECREMENT); WindowInitScrollWidgets(*this); WindowPushOthersBelow(*this); @@ -287,23 +286,23 @@ namespace OpenRCT2::Ui::Windows if (gLandRemainingOwnershipSales == 0) { SetWidgetDisabled(WIDX_BUY_LAND_RIGHTS, true); - window_land_rights_widgets[WIDX_BUY_LAND_RIGHTS].tooltip = STR_NO_LAND_RIGHTS_FOR_SALE_TIP; + widgets[WIDX_BUY_LAND_RIGHTS].tooltip = STR_NO_LAND_RIGHTS_FOR_SALE_TIP; } else { SetWidgetDisabled(WIDX_BUY_LAND_RIGHTS, false); - window_land_rights_widgets[WIDX_BUY_LAND_RIGHTS].tooltip = STR_BUY_LAND_RIGHTS_TIP; + widgets[WIDX_BUY_LAND_RIGHTS].tooltip = STR_BUY_LAND_RIGHTS_TIP; } if (gLandRemainingConstructionSales == 0) { SetWidgetDisabled(WIDX_BUY_CONSTRUCTION_RIGHTS, true); - window_land_rights_widgets[WIDX_BUY_CONSTRUCTION_RIGHTS].tooltip = STR_NO_CONSTRUCTION_RIGHTS_FOR_SALE_TIP; + widgets[WIDX_BUY_CONSTRUCTION_RIGHTS].tooltip = STR_NO_CONSTRUCTION_RIGHTS_FOR_SALE_TIP; } else { SetWidgetDisabled(WIDX_BUY_CONSTRUCTION_RIGHTS, false); - window_land_rights_widgets[WIDX_BUY_CONSTRUCTION_RIGHTS].tooltip = STR_BUY_CONSTRUCTION_RIGHTS_TIP; + widgets[WIDX_BUY_CONSTRUCTION_RIGHTS].tooltip = STR_BUY_CONSTRUCTION_RIGHTS_TIP; } // Position land size tool @@ -359,7 +358,7 @@ namespace OpenRCT2::Ui::Windows void OnPrepareDraw() override { SetWidgetPressed(WIDX_PREVIEW, true); - window_land_rights_widgets[WIDX_PREVIEW].image = ImageId(LandTool::SizeToSpriteIndex(gLandToolSize)); + widgets[WIDX_PREVIEW].image = ImageId(LandTool::SizeToSpriteIndex(gLandToolSize)); if (width != GetModeDimensions().x) OnResize(); @@ -393,8 +392,8 @@ namespace OpenRCT2::Ui::Windows void OnDraw(DrawPixelInfo& dpi) override { - auto screenCoords = ScreenCoordsXY{ windowPos.x + window_land_rights_widgets[WIDX_PREVIEW].midX(), - windowPos.y + window_land_rights_widgets[WIDX_PREVIEW].midY() }; + auto screenCoords = ScreenCoordsXY{ windowPos.x + widgets[WIDX_PREVIEW].midX(), + windowPos.y + widgets[WIDX_PREVIEW].midY() }; DrawWidgets(dpi); // Draw number for tool sizes bigger than 7 @@ -415,8 +414,8 @@ namespace OpenRCT2::Ui::Windows auto offset = widgets[WIDX_BUY_LAND_RIGHTS].type != WindowWidgetType::Empty ? 32 : 8; - screenCoords = { window_land_rights_widgets[WIDX_PREVIEW].midX() + windowPos.x, - window_land_rights_widgets[WIDX_PREVIEW].bottom + windowPos.y + offset }; + screenCoords = { widgets[WIDX_PREVIEW].midX() + windowPos.x, + widgets[WIDX_PREVIEW].bottom + windowPos.y + offset }; DrawTextBasic(dpi, screenCoords, STR_COST_AMOUNT, ft, { TextAlignment::CENTRE }); } } diff --git a/src/openrct2-ui/windows/LoadSave.cpp b/src/openrct2-ui/windows/LoadSave.cpp index f096cea754..c260c2e776 100644 --- a/src/openrct2-ui/windows/LoadSave.cpp +++ b/src/openrct2-ui/windows/LoadSave.cpp @@ -80,7 +80,7 @@ namespace OpenRCT2::Ui::Windows static constexpr int16_t WH = kWindowSizeInit.height; // clang-format off - static Widget window_loadsave_widgets[] = + static constexpr Widget window_loadsave_widgets[] = { WINDOW_SHIM(STR_NONE, WW, WH), MakeWidget({ 0, 15 }, { WW, WH - 15 }, WindowWidgetType::Resize, WindowColour::Secondary ), // WIDX_RESIZE @@ -96,7 +96,6 @@ namespace OpenRCT2::Ui::Windows MakeWidget({ 64, WH - 50 }, { WW - 133, 14 }, WindowWidgetType::TextBox, WindowColour::Secondary ), // WIDX_FILENAME_TEXTBOX MakeWidget({ WW - 65, WH - 50 }, { 60, 14 }, WindowWidgetType::Button, WindowColour::Secondary, STR_FILEBROWSER_SAVE_BUTTON ), // WIDX_SAVE MakeWidget({ 4, WH - 24 }, { 197, 19 }, WindowWidgetType::Button, WindowColour::Primary, STR_FILEBROWSER_USE_SYSTEM_WINDOW ), // WIDX_BROWSE - kWidgetsEnd, }; // clang-format on @@ -713,7 +712,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = window_loadsave_widgets; + SetWidgets(window_loadsave_widgets); const auto uiContext = OpenRCT2::GetContext()->GetUiContext(); if (!uiContext->HasFilePicker()) @@ -1422,11 +1421,10 @@ namespace OpenRCT2::Ui::Windows }; // clang-format off - static Widget window_overwrite_prompt_widgets[] = { + static constexpr Widget window_overwrite_prompt_widgets[] = { WINDOW_SHIM_WHITE(STR_FILEBROWSER_OVERWRITE_TITLE, OVERWRITE_WW, OVERWRITE_WH), MakeWidget({ 10, OVERWRITE_WH - 20 }, { 84, 11 }, WindowWidgetType::Button, WindowColour::Primary, STR_FILEBROWSER_OVERWRITE_TITLE), MakeWidget({ OVERWRITE_WW - 95, OVERWRITE_WH - 20 }, { 85, 11 }, WindowWidgetType::Button, WindowColour::Primary, STR_SAVE_PROMPT_CANCEL), - kWidgetsEnd, }; // clang-format on @@ -1444,7 +1442,7 @@ namespace OpenRCT2::Ui::Windows void OnOpen() override { - widgets = window_overwrite_prompt_widgets; + SetWidgets(window_overwrite_prompt_widgets); } void OnMouseUp(WidgetIndex widgetIndex) override diff --git a/src/openrct2-ui/windows/Main.cpp b/src/openrct2-ui/windows/Main.cpp index 1e12faaf49..7710a0fce7 100644 --- a/src/openrct2-ui/windows/Main.cpp +++ b/src/openrct2-ui/windows/Main.cpp @@ -19,9 +19,8 @@ namespace OpenRCT2::Ui::Windows { // clang-format off - static Widget _mainWidgets[] = { + static constexpr Widget _mainWidgets[] = { MakeWidget({0, 0}, {0, 0}, WindowWidgetType::Viewport, WindowColour::Primary), - kWidgetsEnd, }; // clang-format on @@ -30,9 +29,9 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - _mainWidgets[0].right = width; - _mainWidgets[0].bottom = height; - widgets = _mainWidgets; + SetWidgets(_mainWidgets); + widgets[0].right = width; + widgets[0].bottom = height; ViewportCreate(this, windowPos, width, height, Focus(CoordsXYZ(0x0FFF, 0x0FFF, 0))); if (viewport != nullptr) diff --git a/src/openrct2-ui/windows/Map.cpp b/src/openrct2-ui/windows/Map.cpp index 4e7302d156..a67ce9e820 100644 --- a/src/openrct2-ui/windows/Map.cpp +++ b/src/openrct2-ui/windows/Map.cpp @@ -132,7 +132,7 @@ namespace OpenRCT2::Ui::Windows }; // clang-format off - static Widget window_map_widgets[] = { + static constexpr Widget window_map_widgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), MakeWidget ({ 0, 43}, {245, 215}, WindowWidgetType::Resize, WindowColour::Secondary ), MakeRemapWidget ({ 3, 17}, { 31, 27}, WindowWidgetType::ColourBtn, WindowColour::Secondary, SPR_TAB, STR_SHOW_PEOPLE_ON_MAP_TIP ), @@ -145,7 +145,6 @@ namespace OpenRCT2::Ui::Windows MakeWidget ({ 4, 70}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_G2_PEEP_SPAWN), STR_SET_STARTING_POSITIONS_TIP ), MakeWidget ({ 28, 94}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_PARK_ENTRANCE), STR_BUILD_PARK_ENTRANCE_TIP ), MakeWidget ({110, 118}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_G2_MAP_GEN_BTN), STR_MAP_GENERATOR_TIP ), - kWidgetsEnd, }; // clang-format on @@ -235,7 +234,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = window_map_widgets; + SetWidgets(window_map_widgets); hold_down_widgets = (1uLL << WIDX_MAP_SIZE_SPINNER_Y_UP) | (1uLL << WIDX_MAP_SIZE_SPINNER_Y_DOWN) | (1uLL << WIDX_MAP_SIZE_SPINNER_X_UP) | (1uLL << WIDX_MAP_SIZE_SPINNER_X_DOWN); diff --git a/src/openrct2-ui/windows/MapGen.cpp b/src/openrct2-ui/windows/MapGen.cpp index e8f41533e1..23e52cd643 100644 --- a/src/openrct2-ui/windows/MapGen.cpp +++ b/src/openrct2-ui/windows/MapGen.cpp @@ -124,7 +124,7 @@ namespace OpenRCT2::Ui::Windows MakeWidget({ 185, 200 }, { 109, 14 }, WindowWidgetType::Button, WindowColour::Secondary, STR_MAPGEN_ACTION_GENERATE) // clang-format off - static Widget BaseWidgets[] = { + static constexpr Widget BaseWidgets[] = { SHARED_WIDGETS(STR_MAPGEN_CAPTION_GENERATOR), MakeSpinnerWidgets ({165, 52}, { 50, 12}, WindowWidgetType::Spinner, WindowColour::Secondary, STR_COMMA16 ), // NB: 3 widgets MakeWidget ({216, 52}, { 21, 12}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_G2_LINK_CHAIN), STR_MAINTAIN_SQUARE_MAP_TOOLTIP), @@ -140,10 +140,9 @@ namespace OpenRCT2::Ui::Windows MakeWidget ({ 10, 125}, {150, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_MAPGEN_NORMALIZE ), // WIDX_HEIGHTMAP_NORMALIZE MakeWidget ({ 10, 141}, {150, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_MAPGEN_SMOOTH_HEIGHTMAP), // WIDX_HEIGHTMAP_SMOOTH_HEIGHTMAP MakeSpinnerWidgets({179, 157}, {109, 12}, WindowWidgetType::Spinner, WindowColour::Secondary ), // WIDX_HEIGHTMAP_STRENGTH{,_UP,_DOWN} - kWidgetsEnd, }; - static Widget TerrainWidgets[] = { + static constexpr Widget TerrainWidgets[] = { SHARED_WIDGETS(STR_MAPGEN_CAPTION_TERRAIN), MakeSpinnerWidgets({179, 52}, {109, 12}, WindowWidgetType::Spinner, WindowColour::Secondary ), // WIDX_HEIGHTMAP_LOW{,_UP,_DOWN} MakeSpinnerWidgets({179, 70}, {109, 12}, WindowWidgetType::Spinner, WindowColour::Secondary ), // WIDX_HEIGHTMAP_HIGH{,_UP,_DOWN} @@ -151,26 +150,23 @@ namespace OpenRCT2::Ui::Windows MakeWidget ({236, 88}, { 47, 36}, WindowWidgetType::FlatBtn, WindowColour::Secondary, 0xFFFFFFFF, STR_CHANGE_VERTICAL_LAND_TIP), MakeWidget ({ 10, 106}, {150, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_MAPGEN_OPTION_RANDOM_TERRAIN ), MakeWidget ({ 10, 122}, {150, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_MAPGEN_SMOOTH_TILE), // WIDX_HEIGHTMAP_SMOOTH_TILE_EDGES - kWidgetsEnd, }; - static Widget WaterWidgets[] = { + static constexpr Widget WaterWidgets[] = { SHARED_WIDGETS(STR_MAPGEN_CAPTION_WATER), MakeSpinnerWidgets({179, 52}, {109, 12}, WindowWidgetType::Spinner, WindowColour::Secondary ), // NB: 3 widgets MakeWidget ({ 10, 70}, {195, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_BEACHES_WATER_BODIES), - kWidgetsEnd, }; - static Widget ForestsWidgets[] = { + static constexpr Widget ForestsWidgets[] = { SHARED_WIDGETS(STR_MAPGEN_CAPTION_FORESTS), MakeWidget ({ 10, 52}, {255, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_MAPGEN_OPTION_PLACE_TREES), MakeSpinnerWidgets({179, 70}, {109, 12}, WindowWidgetType::Spinner, WindowColour::Secondary), // WIDX_TREE_LAND_RATIO{,_UP,_DOWN} MakeSpinnerWidgets({179, 88}, {109, 12}, WindowWidgetType::Spinner, WindowColour::Secondary), // WIDX_TREE_ALTITUDE_MIN{,_UP,_DOWN} MakeSpinnerWidgets({179, 106}, {109, 12}, WindowWidgetType::Spinner, WindowColour::Secondary), // WIDX_TREE_ALTITUDE_MAX{,_UP,_DOWN} - kWidgetsEnd, }; - static Widget* PageWidgets[WINDOW_MAPGEN_PAGE_COUNT] = { + static std::span PageWidgets[WINDOW_MAPGEN_PAGE_COUNT] = { BaseWidgets, TerrainWidgets, WaterWidgets, @@ -282,7 +278,7 @@ namespace OpenRCT2::Ui::Windows RemoveViewport(); hold_down_widgets = HoldDownWidgets[newPage]; - widgets = PageWidgets[newPage]; + SetWidgets(PageWidgets[newPage]); disabled_widgets = PageDisabledWidgets[newPage]; pressed_widgets = PressedWidgets[newPage]; @@ -515,12 +511,6 @@ namespace OpenRCT2::Ui::Windows void BasePrepareDraw() { - if (widgets != PageWidgets[WINDOW_MAPGEN_PAGE_BASE]) - { - widgets = PageWidgets[WINDOW_MAPGEN_PAGE_BASE]; - InitScrollWidgets(); - } - // Only allow linking the map size when X and Y are the same SetWidgetPressed(WIDX_MAP_SIZE_LINK, _mapWidthAndHeightLinked); SetWidgetDisabled(WIDX_MAP_SIZE_LINK, _settings.mapSize.x != _settings.mapSize.y); @@ -578,26 +568,26 @@ namespace OpenRCT2::Ui::Windows void ToggleSimplexWidgets(bool state) { // clang-format off - BaseWidgets[WIDX_SIMPLEX_GROUP].type = state ? WindowWidgetType::Groupbox : WindowWidgetType::Empty; - BaseWidgets[WIDX_SIMPLEX_BASE_FREQ].type = state ? WindowWidgetType::Spinner : WindowWidgetType::Empty; - BaseWidgets[WIDX_SIMPLEX_BASE_FREQ_UP].type = state ? WindowWidgetType::Button : WindowWidgetType::Empty; - BaseWidgets[WIDX_SIMPLEX_BASE_FREQ_DOWN].type = state ? WindowWidgetType::Button : WindowWidgetType::Empty; - BaseWidgets[WIDX_SIMPLEX_OCTAVES].type = state ? WindowWidgetType::Spinner : WindowWidgetType::Empty; - BaseWidgets[WIDX_SIMPLEX_OCTAVES_UP].type = state ? WindowWidgetType::Button : WindowWidgetType::Empty; - BaseWidgets[WIDX_SIMPLEX_OCTAVES_DOWN].type = state ? WindowWidgetType::Button : WindowWidgetType::Empty; + widgets[WIDX_SIMPLEX_GROUP].type = state ? WindowWidgetType::Groupbox : WindowWidgetType::Empty; + widgets[WIDX_SIMPLEX_BASE_FREQ].type = state ? WindowWidgetType::Spinner : WindowWidgetType::Empty; + widgets[WIDX_SIMPLEX_BASE_FREQ_UP].type = state ? WindowWidgetType::Button : WindowWidgetType::Empty; + widgets[WIDX_SIMPLEX_BASE_FREQ_DOWN].type = state ? WindowWidgetType::Button : WindowWidgetType::Empty; + widgets[WIDX_SIMPLEX_OCTAVES].type = state ? WindowWidgetType::Spinner : WindowWidgetType::Empty; + widgets[WIDX_SIMPLEX_OCTAVES_UP].type = state ? WindowWidgetType::Button : WindowWidgetType::Empty; + widgets[WIDX_SIMPLEX_OCTAVES_DOWN].type = state ? WindowWidgetType::Button : WindowWidgetType::Empty; // clang-format on } void ToggleHeightmapWidgets(bool state) { // clang-format off - BaseWidgets[WIDX_HEIGHTMAP_GROUP].type = state ? WindowWidgetType::Groupbox : WindowWidgetType::Empty; - BaseWidgets[WIDX_HEIGHTMAP_BROWSE].type = state ? WindowWidgetType::Button : WindowWidgetType::Empty; - BaseWidgets[WIDX_HEIGHTMAP_NORMALIZE].type = state ? WindowWidgetType::Checkbox : WindowWidgetType::Empty; - BaseWidgets[WIDX_HEIGHTMAP_SMOOTH_HEIGHTMAP].type = state ? WindowWidgetType::Checkbox : WindowWidgetType::Empty; - BaseWidgets[WIDX_HEIGHTMAP_STRENGTH].type = state ? WindowWidgetType::Spinner : WindowWidgetType::Empty; - BaseWidgets[WIDX_HEIGHTMAP_STRENGTH_UP].type = state ? WindowWidgetType::Button : WindowWidgetType::Empty; - BaseWidgets[WIDX_HEIGHTMAP_STRENGTH_DOWN].type = state ? WindowWidgetType::Button : WindowWidgetType::Empty; + widgets[WIDX_HEIGHTMAP_GROUP].type = state ? WindowWidgetType::Groupbox : WindowWidgetType::Empty; + widgets[WIDX_HEIGHTMAP_BROWSE].type = state ? WindowWidgetType::Button : WindowWidgetType::Empty; + widgets[WIDX_HEIGHTMAP_NORMALIZE].type = state ? WindowWidgetType::Checkbox : WindowWidgetType::Empty; + widgets[WIDX_HEIGHTMAP_SMOOTH_HEIGHTMAP].type = state ? WindowWidgetType::Checkbox : WindowWidgetType::Empty; + widgets[WIDX_HEIGHTMAP_STRENGTH].type = state ? WindowWidgetType::Spinner : WindowWidgetType::Empty; + widgets[WIDX_HEIGHTMAP_STRENGTH_UP].type = state ? WindowWidgetType::Button : WindowWidgetType::Empty; + widgets[WIDX_HEIGHTMAP_STRENGTH_DOWN].type = state ? WindowWidgetType::Button : WindowWidgetType::Empty; // clang-format on } @@ -744,12 +734,6 @@ namespace OpenRCT2::Ui::Windows void ForestsPrepareDraw() { - if (widgets != PageWidgets[WINDOW_MAPGEN_PAGE_FORESTS]) - { - widgets = PageWidgets[WINDOW_MAPGEN_PAGE_FORESTS]; - InitScrollWidgets(); - } - pressed_widgets = 0; if (_settings.trees) pressed_widgets |= 1uLL << WIDX_FORESTS_PLACE_TREES; @@ -1221,12 +1205,6 @@ namespace OpenRCT2::Ui::Windows void TerrainPrepareDraw() { - if (widgets != PageWidgets[WINDOW_MAPGEN_PAGE_TERRAIN]) - { - widgets = PageWidgets[WINDOW_MAPGEN_PAGE_TERRAIN]; - InitScrollWidgets(); - } - SetCheckboxValue(WIDX_RANDOM_TERRAIN, _randomTerrain != 0); SetCheckboxValue(WIDX_HEIGHTMAP_SMOOTH_TILE_EDGES, _settings.smoothTileEdges); @@ -1348,12 +1326,6 @@ namespace OpenRCT2::Ui::Windows void WaterPrepareDraw() { - if (widgets != PageWidgets[WINDOW_MAPGEN_PAGE_WATER]) - { - widgets = PageWidgets[WINDOW_MAPGEN_PAGE_WATER]; - InitScrollWidgets(); - } - SetCheckboxValue(WIDX_ADD_BEACHES, _settings.beaches != 0); SetPressedTab(); @@ -1383,11 +1355,9 @@ namespace OpenRCT2::Ui::Windows void OnOpen() override { number = 0; - frame_no = 0; - page = WINDOW_MAPGEN_PAGE_BASE; + SetPage(WINDOW_MAPGEN_PAGE_BASE); Invalidate(); - widgets = PageWidgets[WINDOW_MAPGEN_PAGE_BASE]; hold_down_widgets = HoldDownWidgets[WINDOW_MAPGEN_PAGE_BASE]; pressed_widgets = PressedWidgets[WINDOW_MAPGEN_PAGE_BASE]; disabled_widgets = PageDisabledWidgets[WINDOW_MAPGEN_PAGE_BASE]; diff --git a/src/openrct2-ui/windows/MapTooltip.cpp b/src/openrct2-ui/windows/MapTooltip.cpp index 71ee35120f..3a77481343 100644 --- a/src/openrct2-ui/windows/MapTooltip.cpp +++ b/src/openrct2-ui/windows/MapTooltip.cpp @@ -22,9 +22,8 @@ namespace OpenRCT2::Ui::Windows { // clang-format off - static Widget window_map_tooltip_widgets[] = { + static constexpr Widget window_map_tooltip_widgets[] = { MakeWidget({0, 0}, {200, 30}, WindowWidgetType::ImgBtn, WindowColour::Primary), - kWidgetsEnd, }; // clang-format on @@ -40,7 +39,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = window_map_tooltip_widgets; + SetWidgets(window_map_tooltip_widgets); } void OnUpdate() override diff --git a/src/openrct2-ui/windows/MazeConstruction.cpp b/src/openrct2-ui/windows/MazeConstruction.cpp index 16ec9830af..b64393bb22 100644 --- a/src/openrct2-ui/windows/MazeConstruction.cpp +++ b/src/openrct2-ui/windows/MazeConstruction.cpp @@ -61,7 +61,7 @@ namespace OpenRCT2::Ui::Windows validate_global_widx(WC_MAZE_CONSTRUCTION, WIDX_MAZE_EXIT); // clang-format off - static Widget window_maze_construction_widgets[] = { + static constexpr Widget window_maze_construction_widgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), MakeWidget({ 3, 17}, {160, 55}, WindowWidgetType::Groupbox, WindowColour::Primary , STR_RIDE_CONSTRUCTION_MODE ), MakeWidget({ 0, 0}, { 1, 1}, WindowWidgetType::Empty, WindowColour::Primary ), @@ -94,7 +94,6 @@ namespace OpenRCT2::Ui::Windows MakeWidget({87, 178}, { 70, 12}, WindowWidgetType::Button, WindowColour::Secondary, STR_RIDE_CONSTRUCTION_EXIT, STR_RIDE_CONSTRUCTION_EXIT_TIP ), MakeWidget({ 0, 0}, { 1, 1}, WindowWidgetType::Empty, WindowColour::Primary ), MakeWidget({ 0, 0}, { 1, 1}, WindowWidgetType::Empty, WindowColour::Primary ), - kWidgetsEnd, }; // clang-format on @@ -105,7 +104,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = window_maze_construction_widgets; + SetWidgets(window_maze_construction_widgets); WindowInitScrollWidgets(*this); rideId = _currentRideIndex; ShowGridlines(); diff --git a/src/openrct2-ui/windows/Multiplayer.cpp b/src/openrct2-ui/windows/Multiplayer.cpp index 07fd363ab3..a846142952 100644 --- a/src/openrct2-ui/windows/Multiplayer.cpp +++ b/src/openrct2-ui/windows/Multiplayer.cpp @@ -72,22 +72,20 @@ namespace OpenRCT2::Ui::Windows MakeTab ({ 65, 17}, STR_GROUPS_TIP ), /* tab */ \ MakeTab ({ 96, 17}, STR_OPTIONS_TIP ) /* tab */ - static Widget window_multiplayer_information_widgets[] = { + static constexpr Widget window_multiplayer_information_widgets[] = { MAIN_MULTIPLAYER_WIDGETS, - kWidgetsEnd, }; - static Widget window_multiplayer_players_widgets[] = { + static constexpr Widget window_multiplayer_players_widgets[] = { MAIN_MULTIPLAYER_WIDGETS, MakeWidget({ 3, 46}, {173, 15}, WindowWidgetType::TableHeader, WindowColour::Primary , STR_PLAYER ), // Player name MakeWidget({176, 46}, { 83, 15}, WindowWidgetType::TableHeader, WindowColour::Primary , STR_GROUP ), // Player name MakeWidget({259, 46}, {100, 15}, WindowWidgetType::TableHeader, WindowColour::Primary , STR_LAST_ACTION), // Player name MakeWidget({359, 46}, { 42, 15}, WindowWidgetType::TableHeader, WindowColour::Primary , STR_PING ), // Player name MakeWidget({ 3, 60}, {334, 177}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_VERTICAL), // list - kWidgetsEnd, }; - static Widget window_multiplayer_groups_widgets[] = { + static constexpr Widget window_multiplayer_groups_widgets[] = { MAIN_MULTIPLAYER_WIDGETS, MakeWidget({141, 46}, {175, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary ), // default group MakeWidget({305, 47}, { 11, 10}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH), @@ -97,18 +95,16 @@ namespace OpenRCT2::Ui::Windows MakeWidget({ 72, 80}, {175, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary ), // selected group MakeWidget({236, 81}, { 11, 10}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH), MakeWidget({ 3, 94}, {314, 207}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_VERTICAL ), // permissions list - kWidgetsEnd, }; - static Widget window_multiplayer_options_widgets[] = { + static constexpr Widget window_multiplayer_options_widgets[] = { MAIN_MULTIPLAYER_WIDGETS, MakeWidget({3, 50}, {295, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_LOG_CHAT, STR_LOG_CHAT_TIP ), MakeWidget({3, 64}, {295, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_LOG_SERVER_ACTIONS, STR_LOG_SERVER_ACTIONS_TIP ), MakeWidget({3, 78}, {295, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_ALLOW_KNOWN_KEYS_ONLY, STR_ALLOW_KNOWN_KEYS_ONLY_TIP), - kWidgetsEnd, }; - static Widget *window_multiplayer_page_widgets[] = { + static std::span window_multiplayer_page_widgets[] = { window_multiplayer_information_widgets, window_multiplayer_players_widgets, window_multiplayer_groups_widgets, @@ -214,7 +210,7 @@ namespace OpenRCT2::Ui::Windows hold_down_widgets = 0; pressed_widgets = 0; - widgets = window_multiplayer_page_widgets[page]; + SetWidgets(window_multiplayer_page_widgets[page]); widgets[WIDX_TITLE].text = WindowMultiplayerPageTitles[page]; OnResize(); @@ -405,15 +401,15 @@ namespace OpenRCT2::Ui::Windows } case WINDOW_MULTIPLAYER_PAGE_PLAYERS: { - window_multiplayer_players_widgets[WIDX_LIST].right = width - 4; - window_multiplayer_players_widgets[WIDX_LIST].bottom = height - 0x0F; + widgets[WIDX_LIST].right = width - 4; + widgets[WIDX_LIST].bottom = height - 0x0F; WindowAlignTabs(this, WIDX_TAB1, WIDX_TAB4); break; } case WINDOW_MULTIPLAYER_PAGE_GROUPS: { - window_multiplayer_groups_widgets[WIDX_PERMISSIONS_LIST].right = width - 4; - window_multiplayer_groups_widgets[WIDX_PERMISSIONS_LIST].bottom = height - 0x0F; + widgets[WIDX_PERMISSIONS_LIST].right = width - 4; + widgets[WIDX_PERMISSIONS_LIST].bottom = height - 0x0F; WindowAlignTabs(this, WIDX_TAB1, WIDX_TAB4); // select other group if one is removed @@ -530,11 +526,11 @@ namespace OpenRCT2::Ui::Windows gDropdownItems[i].Format = STR_OPTIONS_DROPDOWN_ITEM; gDropdownItems[i].Args = reinterpret_cast(NetworkGetGroupName(i)); } - if (widget == &window_multiplayer_groups_widgets[WIDX_DEFAULT_GROUP_DROPDOWN]) + if (widget == &widgets[WIDX_DEFAULT_GROUP_DROPDOWN]) { Dropdown::SetChecked(NetworkGetGroupIndex(NetworkGetDefaultGroup()), true); } - else if (widget == &window_multiplayer_groups_widgets[WIDX_SELECTED_GROUP_DROPDOWN]) + else if (widget == &widgets[WIDX_SELECTED_GROUP_DROPDOWN]) { Dropdown::SetChecked(NetworkGetGroupIndex(_selectedGroup), true); } @@ -572,8 +568,7 @@ namespace OpenRCT2::Ui::Windows } screenSize = { 0, NetworkGetNumPlayers() * kScrollableRowHeight }; - int32_t i = screenSize.height - window_multiplayer_players_widgets[WIDX_LIST].bottom - + window_multiplayer_players_widgets[WIDX_LIST].top + 21; + int32_t i = screenSize.height - widgets[WIDX_LIST].bottom + widgets[WIDX_LIST].top + 21; if (i < 0) i = 0; if (i < scrolls[0].contentOffsetY) @@ -593,8 +588,7 @@ namespace OpenRCT2::Ui::Windows } screenSize = { 0, NetworkGetNumActions() * kScrollableRowHeight }; - int32_t i = screenSize.height - window_multiplayer_groups_widgets[WIDX_LIST].bottom - + window_multiplayer_groups_widgets[WIDX_LIST].top + 21; + int32_t i = screenSize.height - widgets[WIDX_LIST].bottom + widgets[WIDX_LIST].top + 21; if (i < 0) i = 0; if (i < scrolls[0].contentOffsetY) @@ -842,7 +836,7 @@ namespace OpenRCT2::Ui::Windows { thread_local std::string _buffer; - Widget* widget = &window_multiplayer_groups_widgets[WIDX_DEFAULT_GROUP]; + Widget* widget = &widgets[WIDX_DEFAULT_GROUP]; int32_t group = NetworkGetGroupIndex(NetworkGetDefaultGroup()); if (group != -1) { @@ -857,8 +851,7 @@ namespace OpenRCT2::Ui::Windows } auto screenPos = windowPos - + ScreenCoordsXY{ window_multiplayer_groups_widgets[WIDX_CONTENT_PANEL].left + 4, - window_multiplayer_groups_widgets[WIDX_CONTENT_PANEL].top + 4 }; + + ScreenCoordsXY{ widgets[WIDX_CONTENT_PANEL].left + 4, widgets[WIDX_CONTENT_PANEL].top + 4 }; DrawTextBasic(dpi, screenPos, STR_DEFAULT_GROUP, {}, { colours[2] }); @@ -868,7 +861,7 @@ namespace OpenRCT2::Ui::Windows dpi, { screenPos - ScreenCoordsXY{ 0, 6 }, screenPos + ScreenCoordsXY{ 310, -5 } }, colours[1], INSET_RECT_FLAG_BORDER_INSET); - widget = &window_multiplayer_groups_widgets[WIDX_SELECTED_GROUP]; + widget = &widgets[WIDX_SELECTED_GROUP]; group = NetworkGetGroupIndex(_selectedGroup); if (group != -1) { diff --git a/src/openrct2-ui/windows/NetworkStatus.cpp b/src/openrct2-ui/windows/NetworkStatus.cpp index db730f4a0f..0b80ce3268 100644 --- a/src/openrct2-ui/windows/NetworkStatus.cpp +++ b/src/openrct2-ui/windows/NetworkStatus.cpp @@ -26,11 +26,10 @@ namespace OpenRCT2::Ui::Windows }; // clang-format off - static Widget window_network_status_widgets[] = { + static constexpr Widget window_network_status_widgets[] = { MakeWidget({ 0, 0}, {400, 91}, WindowWidgetType::Frame, WindowColour::Primary ), // panel / background MakeWidget({ 1, 1}, {397, 14}, WindowWidgetType::Caption, WindowColour::Primary, STR_NONE, STR_WINDOW_TITLE_TIP), // title bar MakeWidget({388, 2}, { 11, 12}, WindowWidgetType::CloseBox, WindowColour::Primary, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP), // close x button - kWidgetsEnd, }; // clang-format on @@ -39,7 +38,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = window_network_status_widgets; + SetWidgets(window_network_status_widgets); WindowInitScrollWidgets(*this); frame_no = 0; diff --git a/src/openrct2-ui/windows/NewCampaign.cpp b/src/openrct2-ui/windows/NewCampaign.cpp index e000ad9c2d..1fb2cdcc57 100644 --- a/src/openrct2-ui/windows/NewCampaign.cpp +++ b/src/openrct2-ui/windows/NewCampaign.cpp @@ -50,7 +50,7 @@ namespace OpenRCT2::Ui::Windows }; // clang-format off - static Widget window_new_campaign_widgets[] = { + static constexpr Widget window_new_campaign_widgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), MakeWidget ({ 14, 24}, {126, 12}, WindowWidgetType::Label, WindowColour::Primary, STR_EMPTY ), // ride label MakeWidget ({100, 24}, {242, 12}, WindowWidgetType::DropdownMenu, WindowColour::Primary, STR_EMPTY ), // ride dropdown @@ -58,7 +58,6 @@ namespace OpenRCT2::Ui::Windows MakeWidget ({ 14, 41}, {126, 14}, WindowWidgetType::Label, WindowColour::Primary, STR_LENGTH_OF_TIME ), // weeks label MakeSpinnerWidgets({120, 41}, {100, 14}, WindowWidgetType::Spinner, WindowColour::Primary, STR_EMPTY ), // weeks (3 widgets) MakeWidget ({ 14, 89}, {322, 14}, WindowWidgetType::Button, WindowColour::Primary, STR_MARKETING_START_THIS_MARKETING_CAMPAIGN), // start button - kWidgetsEnd, }; // clang-format on @@ -175,7 +174,7 @@ namespace OpenRCT2::Ui::Windows void OnOpen() override { - widgets = window_new_campaign_widgets; + SetWidgets(window_new_campaign_widgets); hold_down_widgets = (1uLL << WIDX_WEEKS_INCREASE_BUTTON) | (1uLL << WIDX_WEEKS_DECREASE_BUTTON); WindowInitScrollWidgets(*this); } diff --git a/src/openrct2-ui/windows/NewRide.cpp b/src/openrct2-ui/windows/NewRide.cpp index 0837982e8e..e17681f485 100644 --- a/src/openrct2-ui/windows/NewRide.cpp +++ b/src/openrct2-ui/windows/NewRide.cpp @@ -209,7 +209,7 @@ namespace OpenRCT2::Ui::Windows static constexpr ScreenSize GroupTrackTypeSize{ GroupByTrackTypeWidth, 14 }; // clang-format off - static Widget window_new_ride_widgets[] = { + static constexpr Widget window_new_ride_widgets[] = { WINDOW_SHIM(WindowTitle, WindowWidth, WindowHeight), MakeWidget({ 0, 43}, {601, 339}, WindowWidgetType::Resize, WindowColour::Secondary ), MakeTab ({ 3, 17}, STR_TRANSPORT_RIDES_TIP ), @@ -227,7 +227,6 @@ namespace OpenRCT2::Ui::Windows MakeWidget({ 4, 46}, {211, 14}, WindowWidgetType::TextBox, WindowColour::Secondary ), MakeWidget({218, 46}, { 70, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_OBJECT_SEARCH_CLEAR ), MakeWidget(GroupByTrackTypeOrigin, GroupTrackTypeSize, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_GROUP_BY_TRACK_TYPE, STR_GROUP_BY_TRACK_TYPE_TIP ), - kWidgetsEnd, }; // clang-format on @@ -300,7 +299,7 @@ namespace OpenRCT2::Ui::Windows void OnOpen() override { - widgets = window_new_ride_widgets; + SetWidgets(window_new_ride_widgets); PopulateRideList(); InitScrollWidgets(); _filter.clear(); diff --git a/src/openrct2-ui/windows/News.cpp b/src/openrct2-ui/windows/News.cpp index dcfa354f2f..3881d3b223 100644 --- a/src/openrct2-ui/windows/News.cpp +++ b/src/openrct2-ui/windows/News.cpp @@ -39,11 +39,10 @@ namespace OpenRCT2::Ui::Windows }; // clang-format off - static Widget window_news_widgets[] = { + static constexpr Widget window_news_widgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), MakeWidget({372, 18}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Primary, ImageId(SPR_TAB_GEARS_0)), // settings MakeWidget({ 4, 44}, {392, 252}, WindowWidgetType::Scroll, WindowColour::Primary, SCROLL_VERTICAL), // scroll - kWidgetsEnd, }; // clang-format on @@ -59,7 +58,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = window_news_widgets; + SetWidgets(window_news_widgets); WindowInitScrollWidgets(*this); _pressedNewsItemIndex = -1; diff --git a/src/openrct2-ui/windows/NewsOptions.cpp b/src/openrct2-ui/windows/NewsOptions.cpp index c3f952412e..d4f374c8fa 100644 --- a/src/openrct2-ui/windows/NewsOptions.cpp +++ b/src/openrct2-ui/windows/NewsOptions.cpp @@ -72,7 +72,7 @@ namespace OpenRCT2::Ui::Windows }; // clang-format off - static Widget WindowNewsOptionsWidgets[] = { + static constexpr Widget WindowNewsOptionsWidgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), MakeWidget({ 0, 43}, {400, 257}, WindowWidgetType::Resize, WindowColour::Secondary), // Tab content panel MakeTab ({ 3, 17} ), // Park tab @@ -87,7 +87,6 @@ namespace OpenRCT2::Ui::Windows MakeWidget({ 0, 0}, {343, 14}, WindowWidgetType::Checkbox, WindowColour::Tertiary ), MakeWidget({ 0, 0}, {343, 14}, WindowWidgetType::Checkbox, WindowColour::Tertiary ), MakeWidget({ 0, 0}, {343, 14}, WindowWidgetType::Checkbox, WindowColour::Tertiary ), - kWidgetsEnd, }; // clang-format on @@ -96,7 +95,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = WindowNewsOptionsWidgets; + SetWidgets(WindowNewsOptionsWidgets); InitScrollWidgets(); colours[0] = COLOUR_GREY; colours[1] = COLOUR_LIGHT_BLUE; @@ -161,7 +160,7 @@ namespace OpenRCT2::Ui::Windows const auto& baseCheckBox = widgets[WIDX_CHECKBOX_0]; int32_t y = baseCheckBox.top; - int32_t checkboxWidgetIndex = WIDX_CHECKBOX_0; + uint16_t checkboxWidgetIndex = WIDX_CHECKBOX_0; Widget* checkboxWidget = &widgets[checkboxWidgetIndex]; for (size_t i = 0; i < std::size(NewsItemOptionDefinitions); i++) { @@ -185,7 +184,7 @@ namespace OpenRCT2::Ui::Windows } // Remove unused checkboxes - while (checkboxWidget->type != WindowWidgetType::Last) + while (checkboxWidgetIndex < widgets.size()) { checkboxWidget->type = WindowWidgetType::Empty; checkboxWidgetIndex++; diff --git a/src/openrct2-ui/windows/ObjectLoadError.cpp b/src/openrct2-ui/windows/ObjectLoadError.cpp index bfa6916dcb..e10784baa6 100644 --- a/src/openrct2-ui/windows/ObjectLoadError.cpp +++ b/src/openrct2-ui/windows/ObjectLoadError.cpp @@ -279,7 +279,7 @@ namespace OpenRCT2::Ui::Windows constexpr int32_t TYPE_COL_LEFT = 5 * WW_LESS_PADDING / 8 + 1; // clang-format off - static Widget window_object_load_error_widgets[] = { + static constexpr Widget window_object_load_error_widgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), MakeWidget({ NAME_COL_LEFT, 57}, {108, 14}, WindowWidgetType::TableHeader, WindowColour::Primary, STR_OBJECT_NAME ), // 'Object name' header MakeWidget({SOURCE_COL_LEFT, 57}, {166, 14}, WindowWidgetType::TableHeader, WindowColour::Primary, STR_OBJECT_SOURCE ), // 'Object source' header @@ -290,7 +290,6 @@ namespace OpenRCT2::Ui::Windows #ifndef DISABLE_HTTP MakeWidget({ 300, 377}, {146, 14}, WindowWidgetType::Button, WindowColour::Primary, STR_DOWNLOAD_ALL, STR_DOWNLOAD_ALL_TIP ), // Download all button #endif - kWidgetsEnd, }; // clang-format on @@ -397,7 +396,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = window_object_load_error_widgets; + SetWidgets(window_object_load_error_widgets); WindowInitScrollWidgets(*this); colours[0] = COLOUR_LIGHT_BLUE; diff --git a/src/openrct2-ui/windows/Options.cpp b/src/openrct2-ui/windows/Options.cpp index 164390d9f6..fbd8b2a782 100644 --- a/src/openrct2-ui/windows/Options.cpp +++ b/src/openrct2-ui/windows/Options.cpp @@ -248,7 +248,7 @@ namespace OpenRCT2::Ui::Windows MakeTab({ 158, 17 }, STR_OPTIONS_MISCELLANEOUS_TIP), \ MakeTab({ 189, 17 }, STR_OPTIONS_ADVANCED) - static Widget window_options_display_widgets[] = { + static constexpr Widget window_options_display_widgets[] = { MAIN_OPTIONS_WIDGETS, MakeWidget ({ 5, 53}, {300, 170}, WindowWidgetType::Groupbox, WindowColour::Secondary, STR_HARDWARE_GROUP ), // Hardware group MakeWidget ({ 10, 67}, {145, 12}, WindowWidgetType::Label, WindowColour::Secondary, STR_FULLSCREEN_MODE, STR_FULLSCREEN_MODE_TIP ), // Fullscreen @@ -269,13 +269,12 @@ namespace OpenRCT2::Ui::Windows MakeWidget ({ 11, 176}, {143, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_USE_VSYNC, STR_USE_VSYNC_TIP ), // Use vsync MakeWidget ({ 11, 191}, {280, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_MINIMISE_FULLSCREEN_ON_FOCUS_LOSS, STR_MINIMISE_FULLSCREEN_ON_FOCUS_LOSS_TIP), // Minimise fullscreen focus loss MakeWidget ({ 11, 206}, {280, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_DISABLE_SCREENSAVER, STR_DISABLE_SCREENSAVER_TIP ), // Disable screensaver - kWidgetsEnd, }; constexpr int32_t kFrameRenderingStart = 53; constexpr int32_t kFrameEffectStart = 163; - static Widget window_options_rendering_widgets[] = { + static constexpr Widget window_options_rendering_widgets[] = { MAIN_OPTIONS_WIDGETS, MakeWidget({ 5, kFrameRenderingStart + 0}, {300, 108}, WindowWidgetType::Groupbox, WindowColour::Secondary, STR_RENDERING_GROUP ), // Rendering group MakeWidget({ 10, kFrameRenderingStart + 15}, {281, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_TILE_SMOOTHING, STR_TILE_SMOOTHING_TIP ), // Landscape smoothing @@ -293,10 +292,9 @@ namespace OpenRCT2::Ui::Windows MakeWidget({40, kFrameEffectStart + 45}, {251, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_ENABLE_LIGHTING_VEHICLES, STR_ENABLE_LIGHTING_VEHICLES_TIP), // Enable light fx for vehicles MakeWidget({10, kFrameEffectStart + 60}, {281, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_RENDER_WEATHER_EFFECTS, STR_RENDER_WEATHER_EFFECTS_TIP ), // Render weather effects MakeWidget({25, kFrameEffectStart + 75}, {266, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_DISABLE_LIGHTNING_EFFECT, STR_DISABLE_LIGHTNING_EFFECT_TIP), // Disable lightning effect - kWidgetsEnd, }; - static Widget window_options_culture_widgets[] = { + static constexpr Widget window_options_culture_widgets[] = { MAIN_OPTIONS_WIDGETS, MakeWidget({ 10, 53}, {145, 12}, WindowWidgetType::Label, WindowColour::Secondary, STR_OPTIONS_LANGUAGE, STR_LANGUAGE_TIP ), // language MakeWidget({155, 53}, {145, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary, STR_STRING ), @@ -316,10 +314,9 @@ namespace OpenRCT2::Ui::Windows MakeWidget({ 10, 128}, {145, 12}, WindowWidgetType::Label, WindowColour::Secondary, STR_DATE_FORMAT, STR_DATE_FORMAT_TIP ), // Date format MakeWidget({155, 128}, {145, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary ), MakeWidget({288, 129}, { 11, 10}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH, STR_DATE_FORMAT_TIP ), - kWidgetsEnd, }; - static Widget window_options_audio_widgets[] = { + static constexpr Widget window_options_audio_widgets[] = { MAIN_OPTIONS_WIDGETS, MakeWidget({ 10, 53}, {290, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary ), // Audio device MakeWidget({288, 54}, { 11, 10}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH, STR_AUDIO_DEVICE_TIP ), @@ -333,14 +330,13 @@ namespace OpenRCT2::Ui::Windows MakeWidget({155, 68}, {145, 13}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_HORIZONTAL ), // Master volume MakeWidget({155, 83}, {145, 13}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_HORIZONTAL ), // Sound effect volume MakeWidget({155, 98}, {145, 13}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_HORIZONTAL ), // Music volume - kWidgetsEnd, }; constexpr int32_t kControlsGroupStart = 53; constexpr int32_t kThemesGroupStart = 193; constexpr int32_t kToolbarGroupStart = 245; - static Widget window_options_controls_and_interface_widgets[] = { + static constexpr Widget window_options_controls_and_interface_widgets[] = { MAIN_OPTIONS_WIDGETS, MakeWidget({ 5, kControlsGroupStart + 0}, {300,137}, WindowWidgetType::Groupbox, WindowColour::Secondary, STR_CONTROLS_GROUP ), // Controls group MakeWidget({ 10, kControlsGroupStart + 13}, {290, 14}, WindowWidgetType::Checkbox, WindowColour::Tertiary , STR_SCREEN_EDGE_SCROLLING, STR_SCREEN_EDGE_SCROLLING_TIP ), // Edge scrolling @@ -368,7 +364,6 @@ namespace OpenRCT2::Ui::Windows MakeWidget({ 24, kToolbarGroupStart + 76}, {162, 12}, WindowWidgetType::Checkbox, WindowColour::Tertiary , STR_MUTE_BUTTON_ON_TOOLBAR, STR_MUTE_BUTTON_ON_TOOLBAR_TIP ), // Mute MakeWidget({155, kToolbarGroupStart + 76}, {145, 12}, WindowWidgetType::Checkbox, WindowColour::Tertiary , STR_CHAT_BUTTON_ON_TOOLBAR, STR_CHAT_BUTTON_ON_TOOLBAR_TIP ), // Chat MakeWidget({ 24, kToolbarGroupStart + 91}, {122, 12}, WindowWidgetType::Checkbox, WindowColour::Tertiary , STR_ZOOM_BUTTON_ON_TOOLBAR, STR_ZOOM_BUTTON_ON_TOOLBAR_TIP ), // Zoom - kWidgetsEnd, }; constexpr int32_t kTitleSequenceStart = 53; @@ -376,7 +371,7 @@ namespace OpenRCT2::Ui::Windows constexpr int32_t kScenarioOptionsGroupStart = kScenarioGroupStart + 55; constexpr int32_t kTweaksStart = kScenarioOptionsGroupStart + 39; - static Widget window_options_misc_widgets[] = { + static constexpr Widget window_options_misc_widgets[] = { MAIN_OPTIONS_WIDGETS, MakeWidget( { 5, kTitleSequenceStart + 0}, {300, 31}, WindowWidgetType::Groupbox, WindowColour::Secondary, STR_OPTIONS_TITLE_SEQUENCE ), MakeDropdownWidgets({ 10, kTitleSequenceStart + 15}, {290, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary, STR_STRINGID, STR_TITLE_SEQUENCE_TIP), // Title sequence dropdown @@ -398,10 +393,9 @@ namespace OpenRCT2::Ui::Windows MakeWidget({ 10, kTweaksStart + 77}, {165, 12}, WindowWidgetType::Label, WindowColour::Secondary, STR_DEFAULT_INSPECTION_INTERVAL, STR_DEFAULT_INSPECTION_INTERVAL_TIP), MakeWidget({175, kTweaksStart + 76}, {125, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary ), // Default inspection time dropdown MakeWidget({288, kTweaksStart + 77}, { 11, 10}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH, STR_DEFAULT_INSPECTION_INTERVAL_TIP ), // Default inspection time dropdown button - kWidgetsEnd, }; - static Widget window_options_advanced_widgets[] = { + static constexpr Widget window_options_advanced_widgets[] = { MAIN_OPTIONS_WIDGETS, MakeWidget ({ 10, 54}, {290, 12}, WindowWidgetType::Checkbox, WindowColour::Tertiary, STR_ENABLE_DEBUGGING_TOOLS, STR_ENABLE_DEBUGGING_TOOLS_TIP ), // Enable debugging tools MakeWidget ({ 10, 69}, {290, 12}, WindowWidgetType::Checkbox, WindowColour::Tertiary, STR_SAVE_PLUGIN_DATA, STR_SAVE_PLUGIN_DATA_TIP ), // Export plug-in objects with saved games @@ -420,10 +414,9 @@ namespace OpenRCT2::Ui::Windows MakeWidget ({150, 192}, {150, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_EXPORT_EMSCRIPTEN, STR_NONE ), // Emscripten data export MakeWidget ({150, 208}, {150, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_IMPORT_EMSCRIPTEN, STR_NONE ), // Emscripten data import #endif - kWidgetsEnd, }; - static Widget *window_options_page_widgets[] = { + static constexpr std::span window_options_page_widgets[] = { window_options_display_widgets, window_options_rendering_widgets, window_options_culture_widgets, @@ -441,10 +434,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = window_options_display_widgets; - page = WINDOW_OPTIONS_PAGE_DISPLAY; - frame_no = 0; - InitScrollWidgets(); + SetPage(WINDOW_OPTIONS_PAGE_DISPLAY); } void OnMouseUp(WidgetIndex widgetIndex) override @@ -663,11 +653,6 @@ namespace OpenRCT2::Ui::Windows void CommonPrepareDrawBefore() { - if (window_options_page_widgets[page] != widgets) - { - widgets = window_options_page_widgets[page]; - InitScrollWidgets(); - } SetPressedTab(); disabled_widgets = 0; @@ -684,9 +669,10 @@ namespace OpenRCT2::Ui::Windows { // Automatically adjust window height to fit widgets int32_t y = 0; - for (auto widget = &widgets[WIDX_PAGE_START]; widget->type != WindowWidgetType::Last; widget++) + for (WidgetIndex widgetIdx = WIDX_PAGE_START; widgetIdx < widgets.size(); widgetIdx++) { - y = std::max(y, widget->bottom); + const auto& widget = widgets[widgetIdx]; + y = std::max(y, widget.bottom); } height = y + 6; ResizeFrameWithPage(); @@ -2107,7 +2093,7 @@ namespace OpenRCT2::Ui::Windows page = p; frame_no = 0; pressed_widgets = 0; - widgets = window_options_page_widgets[page]; + SetWidgets(window_options_page_widgets[page]); Invalidate(); OnResize(); diff --git a/src/openrct2-ui/windows/Park.cpp b/src/openrct2-ui/windows/Park.cpp index 123efe5141..47b0589674 100644 --- a/src/openrct2-ui/windows/Park.cpp +++ b/src/openrct2-ui/windows/Park.cpp @@ -100,7 +100,7 @@ namespace OpenRCT2::Ui::Windows MakeTab({ 189, 17 }, STR_PARK_AWARDS_TAB_TIP) /* tab 7 */ // clang-format off - static Widget _entranceWidgets[] = { + static constexpr Widget _entranceWidgets[] = { MAIN_PARK_WIDGETS(230), MakeWidget({ 3, 46}, {202, 115}, WindowWidgetType::Viewport, WindowColour::Secondary ), // viewport MakeWidget({ 3, 161}, {202, 11}, WindowWidgetType::LabelCentred, WindowColour::Secondary ), // status @@ -110,43 +110,36 @@ namespace OpenRCT2::Ui::Windows MakeWidget({205, 121}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_RENAME), STR_NAME_PARK_TIP ), // rename MakeWidget({210, 51}, { 14, 15}, WindowWidgetType::ImgBtn, WindowColour::Secondary, ImageId(SPR_G2_RCT1_CLOSE_BUTTON_0), STR_CLOSE_PARK_TIP ), MakeWidget({210, 66}, { 14, 14}, WindowWidgetType::ImgBtn, WindowColour::Secondary, ImageId(SPR_G2_RCT1_OPEN_BUTTON_0), STR_OPEN_PARK_TIP ), - kWidgetsEnd, }; - static Widget _ratingWidgets[] = { + static constexpr Widget _ratingWidgets[] = { MAIN_PARK_WIDGETS(255), - kWidgetsEnd, }; - static Widget _guestsWidgets[] = { + static constexpr Widget _guestsWidgets[] = { MAIN_PARK_WIDGETS(255), - kWidgetsEnd, }; - static Widget _priceWidgets[] = { + static constexpr Widget _priceWidgets[] = { MAIN_PARK_WIDGETS(230), MakeWidget ({ 21, 50}, {126, 14}, WindowWidgetType::Label, WindowColour::Secondary, STR_ADMISSION_PRICE), MakeSpinnerWidgets({147, 50}, { 76, 14}, WindowWidgetType::Spinner, WindowColour::Secondary ), // Price (3 widgets) - kWidgetsEnd, }; - static Widget _statsWidgets[] = { + static constexpr Widget _statsWidgets[] = { MAIN_PARK_WIDGETS(230), - kWidgetsEnd, }; - static Widget _objectiveWidgets[] = { + static constexpr Widget _objectiveWidgets[] = { MAIN_PARK_WIDGETS(230), MakeWidget({7, 207}, {216, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_ENTER_NAME_INTO_SCENARIO_CHART), // enter name - kWidgetsEnd, }; - static Widget _awardsWidgets[] = { + static constexpr Widget _awardsWidgets[] = { MAIN_PARK_WIDGETS(230), - kWidgetsEnd, }; - static std::array _pagedWidgets = { + static std::span _pagedWidgets[] = { _entranceWidgets, _ratingWidgets, _guestsWidgets, @@ -523,7 +516,7 @@ namespace OpenRCT2::Ui::Windows void OnPrepareDrawEntrance() { const auto& gameState = GetGameState(); - widgets = _pagedWidgets[page]; + SetWidgets(_pagedWidgets[page]); InitScrollWidgets(); SetPressedTab(); @@ -701,13 +694,6 @@ namespace OpenRCT2::Ui::Windows void OnPrepareDrawRating() { - auto* ratingWidgets = _pagedWidgets[page]; - if (ratingWidgets != widgets) - { - widgets = ratingWidgets; - InitScrollWidgets(); - } - SetPressedTab(); PrepareWindowTitleText(); @@ -777,13 +763,6 @@ namespace OpenRCT2::Ui::Windows void OnPrepareDrawGuests() { - auto* guestsWidgets = _pagedWidgets[page]; - if (widgets != guestsWidgets) - { - widgets = guestsWidgets; - InitScrollWidgets(); - } - SetPressedTab(); PrepareWindowTitleText(); @@ -887,13 +866,6 @@ namespace OpenRCT2::Ui::Windows void OnPrepareDrawPrice() { - auto* priceWidgets = _pagedWidgets[page]; - if (widgets != priceWidgets) - { - widgets = priceWidgets; - InitScrollWidgets(); - } - SetPressedTab(); PrepareWindowTitleText(); @@ -979,13 +951,6 @@ namespace OpenRCT2::Ui::Windows void OnPrepareDrawStats() { - auto* statsWidgets = _pagedWidgets[page]; - if (widgets != statsWidgets) - { - widgets = statsWidgets; - InitScrollWidgets(); - } - SetPressedTab(); PrepareWindowTitleText(); @@ -1179,13 +1144,6 @@ namespace OpenRCT2::Ui::Windows void OnPrepareDrawAwards() { - auto* awardsWidgets = _pagedWidgets[page]; - if (widgets != awardsWidgets) - { - widgets = awardsWidgets; - InitScrollWidgets(); - } - SetPressedTab(); PrepareWindowTitleText(); @@ -1233,9 +1191,10 @@ namespace OpenRCT2::Ui::Windows RemoveViewport(); hold_down_widgets = _pagedHoldDownWidgets[newPage]; - widgets = _pagedWidgets[newPage]; + SetWidgets(_pagedWidgets[newPage]); SetDisabledTabs(); Invalidate(); + InitScrollWidgets(); OnResize(); OnPrepareDraw(); diff --git a/src/openrct2-ui/windows/PatrolArea.cpp b/src/openrct2-ui/windows/PatrolArea.cpp index ad9eef35ab..0c0129f24e 100644 --- a/src/openrct2-ui/windows/PatrolArea.cpp +++ b/src/openrct2-ui/windows/PatrolArea.cpp @@ -45,12 +45,11 @@ namespace OpenRCT2::Ui::Windows }; // clang-format off - static Widget PatrolAreaWidgets[] = { + static constexpr Widget PatrolAreaWidgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), MakeWidget ({27, 17}, {44, 32}, WindowWidgetType::ImgBtn, WindowColour::Primary , ImageId(SPR_LAND_TOOL_SIZE_0) ), // preview box MakeRemapWidget({28, 18}, {16, 16}, WindowWidgetType::TrnBtn, WindowColour::Tertiary, SPR_LAND_TOOL_DECREASE, STR_ADJUST_SMALLER_PATROL_AREA_TIP), // decrement size MakeRemapWidget({54, 32}, {16, 16}, WindowWidgetType::TrnBtn, WindowColour::Tertiary, SPR_LAND_TOOL_INCREASE, STR_ADJUST_LARGER_PATROL_AREA_TIP ), // increment size - kWidgetsEnd, }; // clang-format on @@ -59,7 +58,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = PatrolAreaWidgets; + SetWidgets(PatrolAreaWidgets); hold_down_widgets = (1uLL << WIDX_INCREMENT) | (1uLL << WIDX_DECREMENT); WindowInitScrollWidgets(*this); WindowPushOthersBelow(*this); @@ -133,7 +132,7 @@ namespace OpenRCT2::Ui::Windows void OnPrepareDraw() override { SetWidgetPressed(WIDX_PREVIEW, true); - PatrolAreaWidgets[WIDX_PREVIEW].image = ImageId(LandTool::SizeToSpriteIndex(gLandToolSize)); + widgets[WIDX_PREVIEW].image = ImageId(LandTool::SizeToSpriteIndex(gLandToolSize)); } void OnDraw(DrawPixelInfo& dpi) override @@ -143,8 +142,8 @@ namespace OpenRCT2::Ui::Windows // Draw number for tool sizes bigger than 7 if (gLandToolSize > kLandToolMaximumSizeWithSprite) { - auto screenCoords = ScreenCoordsXY{ windowPos.x + PatrolAreaWidgets[WIDX_PREVIEW].midX(), - windowPos.y + PatrolAreaWidgets[WIDX_PREVIEW].midY() }; + auto screenCoords = ScreenCoordsXY{ windowPos.x + widgets[WIDX_PREVIEW].midX(), + windowPos.y + widgets[WIDX_PREVIEW].midY() }; auto ft = Formatter(); ft.Add(gLandToolSize); DrawTextBasic( diff --git a/src/openrct2-ui/windows/Player.cpp b/src/openrct2-ui/windows/Player.cpp index 6583dda356..a191327c4a 100644 --- a/src/openrct2-ui/windows/Player.cpp +++ b/src/openrct2-ui/windows/Player.cpp @@ -57,22 +57,20 @@ namespace OpenRCT2::Ui::Windows MakeTab({ 3, 17 }), \ MakeTab({ 34, 17 }) - static Widget window_player_overview_widgets[] = { + static constexpr Widget window_player_overview_widgets[] = { WINDOW_PLAYER_COMMON_WIDGETS, MakeWidget({ 3, 46}, {175, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary ), // Permission group MakeWidget({167, 47}, { 11, 10}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH ), MakeWidget({179, 45}, { 12, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_LOCATE), STR_LOCATE_PLAYER_TIP), // Locate button MakeWidget({179, 69}, { 12, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_DEMOLISH), STR_KICK_PLAYER_TIP ), // Kick button MakeWidget({ 3, 60}, {175, 61}, WindowWidgetType::Viewport, WindowColour::Secondary ), // Viewport - kWidgetsEnd, }; - static Widget window_player_statistics_widgets[] = { + static constexpr Widget window_player_statistics_widgets[] = { WINDOW_PLAYER_COMMON_WIDGETS, - kWidgetsEnd, }; - static Widget *window_player_page_widgets[] = { + static constexpr std::span window_player_page_widgets[] = { window_player_overview_widgets, window_player_statistics_widgets, }; @@ -104,12 +102,9 @@ namespace OpenRCT2::Ui::Windows min_height = 134; max_width = 500; max_height = 450; - - Invalidate(); - - widgets = window_player_page_widgets[WINDOW_PLAYER_PAGE_OVERVIEW]; hold_down_widgets = 0; pressed_widgets = 0; + SetPage(WINDOW_PLAYER_PAGE_OVERVIEW); } void OnResize() override @@ -221,7 +216,7 @@ namespace OpenRCT2::Ui::Windows hold_down_widgets = 0; pressed_widgets = 0; - widgets = window_player_page_widgets[newPage]; + SetWidgets(window_player_page_widgets[newPage]); Invalidate(); OnResize(); OnPrepareDraw(); @@ -376,12 +371,6 @@ namespace OpenRCT2::Ui::Windows return; } - if (window_player_page_widgets[page] != widgets) - { - widgets = window_player_page_widgets[page]; - InitScrollWidgets(); - } - pressed_widgets &= ~(WIDX_TAB_1); pressed_widgets &= ~(WIDX_TAB_2); pressed_widgets |= 1uLL << (page + WIDX_TAB_1); @@ -406,7 +395,7 @@ namespace OpenRCT2::Ui::Windows if (viewport != nullptr) { - Widget* viewportWidget = &window_player_overview_widgets[WIDX_VIEWPORT]; + Widget* viewportWidget = &widgets[WIDX_VIEWPORT]; viewport->pos = windowPos + ScreenCoordsXY{ viewportWidget->left, viewportWidget->top }; viewport->width = viewportWidget->width(); @@ -435,7 +424,7 @@ namespace OpenRCT2::Ui::Windows int32_t groupindex = NetworkGetGroupIndex(NetworkGetPlayerGroup(player)); if (groupindex != -1) { - Widget* widget = &window_player_overview_widgets[WIDX_GROUP]; + Widget* widget = &widgets[WIDX_GROUP]; thread_local std::string _buffer; _buffer.assign("{WINDOW_COLOUR_2}"); @@ -594,12 +583,6 @@ namespace OpenRCT2::Ui::Windows void OnPrepareDrawStatistics() { - if (window_player_page_widgets[page] != widgets) - { - widgets = window_player_page_widgets[page]; - InitScrollWidgets(); - } - pressed_widgets &= ~(WIDX_TAB_1); pressed_widgets &= ~(WIDX_TAB_2); pressed_widgets |= 1uLL << (page + WIDX_TAB_1); @@ -623,8 +606,7 @@ namespace OpenRCT2::Ui::Windows } auto screenCoords = windowPos - + ScreenCoordsXY{ window_player_overview_widgets[WIDX_PAGE_BACKGROUND].left + 4, - window_player_overview_widgets[WIDX_PAGE_BACKGROUND].top + 4 }; + + ScreenCoordsXY{ widgets[WIDX_PAGE_BACKGROUND].left + 4, widgets[WIDX_PAGE_BACKGROUND].top + 4 }; auto ft = Formatter(); ft.Add(NetworkGetPlayerCommandsRan(player)); diff --git a/src/openrct2-ui/windows/ProgressWindow.cpp b/src/openrct2-ui/windows/ProgressWindow.cpp index e9e87dd6f9..dec1db3bec 100644 --- a/src/openrct2-ui/windows/ProgressWindow.cpp +++ b/src/openrct2-ui/windows/ProgressWindow.cpp @@ -34,11 +34,10 @@ namespace OpenRCT2::Ui::Windows static constexpr int32_t kWindowHeight = 90; // clang-format off - static Widget kProgressWindowWidgets[] = { + static constexpr Widget kProgressWindowWidgets[] = { MakeWidget({ 0, 0}, { kWindowWidth, kWindowHeight}, WindowWidgetType::Frame, WindowColour::Primary ), // panel / background MakeWidget({ 1, 1}, {kWindowWidth - 3, 14}, WindowWidgetType::Caption, WindowColour::Primary, STR_STRINGID, STR_WINDOW_TITLE_TIP), // title bar MakeWidget({kWindowWidth - 12, 2}, { 11, 12}, WindowWidgetType::CloseBox, WindowColour::Primary, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP), // close x button - kWidgetsEnd, }; struct LoaderVehicleStyle @@ -85,7 +84,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = kProgressWindowWidgets; + SetWidgets(kProgressWindowWidgets); WindowInitScrollWidgets(*this); frame_no = 0; diff --git a/src/openrct2-ui/windows/RefurbishRidePrompt.cpp b/src/openrct2-ui/windows/RefurbishRidePrompt.cpp index c0a8284928..e157fb33b8 100644 --- a/src/openrct2-ui/windows/RefurbishRidePrompt.cpp +++ b/src/openrct2-ui/windows/RefurbishRidePrompt.cpp @@ -34,12 +34,11 @@ namespace OpenRCT2::Ui::Windows }; // clang-format off - static Widget window_ride_refurbish_widgets[] = + static constexpr Widget window_ride_refurbish_widgets[] = { WINDOW_SHIM_WHITE(STR_REFURBISH_RIDE, WW, WH), MakeWidget({ 10, WH - 22 }, { 85, 14 }, WindowWidgetType::Button, WindowColour::Primary, STR_REFURBISH), MakeWidget({ WW - 95, WH - 22 }, { 85, 14 }, WindowWidgetType::Button, WindowColour::Primary, STR_SAVE_PROMPT_CANCEL), - kWidgetsEnd, }; // clang-format on @@ -56,7 +55,7 @@ namespace OpenRCT2::Ui::Windows void OnOpen() override { - widgets = window_ride_refurbish_widgets; + SetWidgets(window_ride_refurbish_widgets); WindowInitScrollWidgets(*this); } diff --git a/src/openrct2-ui/windows/Research.cpp b/src/openrct2-ui/windows/Research.cpp index f1aff77a4f..7b627ef14c 100644 --- a/src/openrct2-ui/windows/Research.cpp +++ b/src/openrct2-ui/windows/Research.cpp @@ -67,7 +67,7 @@ namespace OpenRCT2::Ui::Windows #pragma region Widgets // clang-format off - static Widget window_research_development_widgets[] = { + static constexpr Widget window_research_development_widgets[] = { WINDOW_SHIM(STR_RESEARCH_AND_DEVELOPMENT, WW_DEVELOPMENT, WH_DEVELOPMENT), MakeWidget({ 0, 43}, { WW_DEVELOPMENT, 153}, WindowWidgetType::Resize, WindowColour::Secondary ), MakeTab ({ 3, 17}, STR_RESEARCH_AND_DEVELOPMENT_TIP), @@ -75,10 +75,9 @@ namespace OpenRCT2::Ui::Windows MakeWidget({ 3, 47}, {WW_DEVELOPMENT - 10, 70}, WindowWidgetType::Groupbox, WindowColour::Tertiary , STR_CURRENTLY_IN_DEVELOPMENT ), MakeWidget({ 3, 124}, {WW_DEVELOPMENT - 10, 65}, WindowWidgetType::Groupbox, WindowColour::Tertiary , STR_LAST_DEVELOPMENT ), MakeWidget({265, 161}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Tertiary , 0xFFFFFFFF, STR_RESEARCH_SHOW_DETAILS_TIP ), - kWidgetsEnd, }; - static Widget window_research_funding_widgets[] = { + static constexpr Widget window_research_funding_widgets[] = { WINDOW_SHIM(STR_RESEARCH_FUNDING, WW_FUNDING, WH_FUNDING), MakeWidget({ 0, 43}, { WW_FUNDING, 164}, WindowWidgetType::Resize, WindowColour::Secondary ), MakeTab ({ 3, 17}, STR_RESEARCH_AND_DEVELOPMENT_TIP ), @@ -94,10 +93,9 @@ namespace OpenRCT2::Ui::Windows MakeWidget({ 8, 160}, {WW_FUNDING - 16, 12}, WindowWidgetType::Checkbox, WindowColour::Tertiary , STR_RESEARCH_NEW_WATER_RIDES, STR_RESEARCH_NEW_WATER_RIDES_TIP ), MakeWidget({ 8, 173}, {WW_FUNDING - 16, 12}, WindowWidgetType::Checkbox, WindowColour::Tertiary , STR_RESEARCH_NEW_SHOPS_AND_STALLS, STR_RESEARCH_NEW_SHOPS_AND_STALLS_TIP ), MakeWidget({ 8, 186}, {WW_FUNDING - 16, 12}, WindowWidgetType::Checkbox, WindowColour::Tertiary , STR_RESEARCH_NEW_SCENERY_AND_THEMING, STR_RESEARCH_NEW_SCENERY_AND_THEMING_TIP ), - kWidgetsEnd, }; - static Widget *window_research_page_widgets[] = { + static constexpr std::span window_research_page_widgets[] = { window_research_development_widgets, window_research_funding_widgets, }; @@ -122,7 +120,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = window_research_page_widgets[WINDOW_RESEARCH_PAGE_DEVELOPMENT]; + SetPage(WINDOW_RESEARCH_PAGE_DEVELOPMENT); width = WW_DEVELOPMENT; height = WH_DEVELOPMENT; ResearchUpdateUncompletedTypes(); @@ -135,7 +133,7 @@ namespace OpenRCT2::Ui::Windows RemoveViewport(); hold_down_widgets = 0; - widgets = window_research_page_widgets[newPageIndex]; + SetWidgets(window_research_page_widgets[newPageIndex]); disabled_widgets = 0; pressed_widgets = 0; @@ -230,14 +228,6 @@ namespace OpenRCT2::Ui::Windows void OnPrepareDraw() override { - auto* targetWidgets = window_research_page_widgets[page]; - - if (widgets != targetWidgets) - { - widgets = targetWidgets; - InitScrollWidgets(); - } - for (auto i = 0; i < WINDOW_RESEARCH_PAGE_COUNT; i++) { SetWidgetPressed(WIDX_TAB_1 + i, false); diff --git a/src/openrct2-ui/windows/Ride.cpp b/src/openrct2-ui/windows/Ride.cpp index fdb04dc8c4..bffe17ffba 100644 --- a/src/openrct2-ui/windows/Ride.cpp +++ b/src/openrct2-ui/windows/Ride.cpp @@ -256,7 +256,7 @@ namespace OpenRCT2::Ui::Windows MakeTab({ 282, 17 }, STR_CUSTOMER_INFORMATION_TIP) // 0x009ADC34 - static Widget _mainWidgets[] = { + static constexpr Widget _mainWidgets[] = { MAIN_RIDE_WIDGETS, MakeWidget({ 3, 60}, {288, 107}, WindowWidgetType::Viewport, WindowColour::Secondary ), MakeWidget({ 35, 46}, {222, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary, kWidgetContentEmpty, STR_VIEW_SELECTION ), @@ -273,11 +273,10 @@ namespace OpenRCT2::Ui::Windows MakeWidget({296, 76}, { 14, 14}, WindowWidgetType::ImgBtn, WindowColour::Secondary, ImageId(SPR_G2_RCT1_OPEN_BUTTON_0), STR_OPEN_RIDE_TIP ), MakeWidget({ 3, 180}, {305, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary, STR_ARG_6_STRINGID ), MakeWidget({297, 180}, { 11, 12}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH ), - kWidgetsEnd, }; // 0x009ADDA8 - static Widget _vehicleWidgets[] = { + static constexpr Widget _vehicleWidgets[] = { MAIN_RIDE_WIDGETS, MakeWidget ({ 7, 50}, {302, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary ), MakeWidget ({297, 51}, { 11, 10}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH ), @@ -285,11 +284,10 @@ namespace OpenRCT2::Ui::Windows MakeWidget ({ 7, 154}, {302, 43}, WindowWidgetType::Scroll, WindowColour::Secondary, STR_EMPTY ), MakeSpinnerWidgets({ 7, 203}, {145, 12}, WindowWidgetType::Spinner, WindowColour::Secondary, STR_RIDE_VEHICLE_COUNT, STR_MAX_VEHICLES_TIP ), MakeSpinnerWidgets({164, 203}, {145, 12}, WindowWidgetType::Spinner, WindowColour::Secondary, STR_1_CAR_PER_TRAIN, STR_MAX_CARS_PER_TRAIN_TIP), - kWidgetsEnd, }; // 0x009ADEFC - static Widget _operatingWidgets[] = { + static constexpr Widget _operatingWidgets[] = { MAIN_RIDE_WIDGETS, MakeSpinnerWidgets({157, 61}, {152, 12}, WindowWidgetType::Spinner, WindowColour::Secondary, STR_ARG_18_STRINGID ), // NB: 3 widgets MakeSpinnerWidgets({157, 75}, {152, 12}, WindowWidgetType::Spinner, WindowColour::Secondary, STR_LIFT_HILL_CHAIN_SPEED_VALUE ), // NB: 3 widgets @@ -308,11 +306,10 @@ namespace OpenRCT2::Ui::Windows MakeWidget ({297, 110}, { 11, 10}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH ), MakeWidget ({ 21, 89}, {129, 12}, WindowWidgetType::Label, WindowColour::Secondary, STR_NUMBER_OF_CIRCUITS, STR_NUMBER_OF_CIRCUITS_TIP ), MakeSpinnerWidgets({157, 89}, {152, 12}, WindowWidgetType::Spinner, WindowColour::Secondary, STR_NUMBER_OF_CIRCUITS_VALUE ), // NB: 3 widgets - kWidgetsEnd, }; // 0x009AE190 - static Widget _maintenanceWidgets[] = { + static constexpr Widget _maintenanceWidgets[] = { MAIN_RIDE_WIDGETS, MakeWidget({107, 71}, {202, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary, STR_EMPTY, STR_SELECT_HOW_OFTEN_A_MECHANIC_SHOULD_CHECK_THIS_RIDE), MakeWidget({297, 72}, { 11, 10}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH, STR_SELECT_HOW_OFTEN_A_MECHANIC_SHOULD_CHECK_THIS_RIDE), @@ -321,11 +318,10 @@ namespace OpenRCT2::Ui::Windows MakeWidget({241, 108}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_NO_ENTRY), STR_DEBUG_FORCE_BREAKDOWN_TIP ), MakeProgressBar({107, 47}, { 147, 10}, COLOUR_BRIGHT_GREEN), MakeProgressBar({107, 58}, { 147, 10}, COLOUR_BRIGHT_RED), - kWidgetsEnd, }; // 0x009AE2A4 - static Widget _colourWidgets[] = { + static constexpr Widget _colourWidgets[] = { MAIN_RIDE_WIDGETS, MakeWidget({ 3, 47}, { 68, 47}, WindowWidgetType::Spinner, WindowColour::Secondary ), MakeWidget({ 74, 49}, {239, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary, STR_ARG_14_STRINGID ), @@ -349,44 +345,40 @@ namespace OpenRCT2::Ui::Windows MakeWidget({119, 190}, { 12, 12}, WindowWidgetType::ColourBtn, WindowColour::Secondary, 0xFFFFFFFF, STR_SELECT_ADDITIONAL_COLOUR_2_TIP ), MakeWidget({100, 74}, {239, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_RANDOM_COLOUR ), MakeWidget({139, 190}, {110, 12}, WindowWidgetType::Button, WindowColour::Secondary, STR_RANDOMISE_VEHICLE_COLOURS, STR_RANDOMISE_VEHICLE_COLOURS_TIP ), - kWidgetsEnd, }; // 0x009AE4C8 - static Widget _musicWidgets[] = { + static constexpr Widget _musicWidgets[] = { MAIN_RIDE_WIDGETS, MakeWidget({ 7, 47}, {302, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_PLAY_MUSIC, STR_SELECT_MUSIC_TIP ), MakeWidget({ 7, 62}, {302, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary, STR_EMPTY ), MakeWidget({297, 63}, { 11, 10}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH, STR_SELECT_MUSIC_STYLE_TIP), MakeWidget({154, 90}, {114, 114}, WindowWidgetType::FlatBtn, WindowColour::Secondary ), MakeWidget({ 7, 90}, {500, 450}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_BOTH ), - kWidgetsEnd, }; // 0x009AE5DC - static Widget _measurementWidgets[] = { + static constexpr Widget _measurementWidgets[] = { MAIN_RIDE_WIDGETS, MakeWidget({288, 194}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_FLOPPY), STR_SAVE_TRACK_DESIGN), MakeWidget({ 4, 127}, {154, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_SELECT_NEARBY_SCENERY ), MakeWidget({158, 127}, {154, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_RESET_SELECTION ), MakeWidget({ 4, 177}, {154, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_DESIGN_SAVE ), MakeWidget({158, 177}, {154, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_DESIGN_CANCEL ), - kWidgetsEnd, }; // 0x009AE710 - static Widget _graphsWidgets[] = { + static constexpr Widget _graphsWidgets[] = { MAIN_RIDE_WIDGETS, MakeWidget({ 3, 46}, {306, 112}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_HORIZONTAL, STR_LOGGING_DATA_FROM_TIP ), MakeWidget({ 3, 163}, { 73, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_RIDE_STATS_VELOCITY, STR_SHOW_GRAPH_OF_VELOCITY_AGAINST_TIME_TIP ), MakeWidget({ 76, 163}, { 73, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_RIDE_STATS_ALTITUDE, STR_SHOW_GRAPH_OF_ALTITUDE_AGAINST_TIME_TIP ), MakeWidget({149, 163}, { 73, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_RIDE_STATS_VERT_G, STR_SHOW_GRAPH_OF_VERTICAL_ACCELERATION_AGAINST_TIME_TIP), MakeWidget({222, 163}, { 73, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_RIDE_STATS_LAT_G, STR_SHOW_GRAPH_OF_LATERAL_ACCELERATION_AGAINST_TIME_TIP ), - kWidgetsEnd, }; // 0x009AE844 - static Widget _incomeWidgets[] = { + static constexpr Widget _incomeWidgets[] = { MAIN_RIDE_WIDGETS, MakeWidget ({ 19, 50}, {126, 14}, WindowWidgetType::Label, WindowColour::Secondary ), MakeSpinnerWidgets({147, 50}, {162, 14}, WindowWidgetType::Spinner, WindowColour::Secondary, STR_ARG_6_CURRENCY2DP ), // NB: 3 widgets @@ -394,19 +386,17 @@ namespace OpenRCT2::Ui::Windows MakeWidget ({ 19, 94}, {126, 14}, WindowWidgetType::Label, WindowColour::Secondary ), MakeSpinnerWidgets({147, 94}, {162, 14}, WindowWidgetType::Spinner, WindowColour::Secondary, STR_RIDE_SECONDARY_PRICE_VALUE ), // NB: 3 widgets MakeWidget ({ 5, 106}, {306, 13}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_SAME_PRICE_THROUGHOUT_PARK, STR_SAME_PRICE_THROUGHOUT_PARK_TIP), - kWidgetsEnd, }; // 0x009AE9C8 - static Widget _customerWidgets[] = { + static constexpr Widget _customerWidgets[] = { MAIN_RIDE_WIDGETS, MakeWidget({289, 54}, {24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_SHOW_GUESTS_THOUGHTS_ABOUT_THIS_RIDE_ATTRACTION), STR_SHOW_GUESTS_THOUGHTS_ABOUT_THIS_RIDE_ATTRACTION_TIP), MakeWidget({289, 78}, {24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_SHOW_GUESTS_ON_THIS_RIDE_ATTRACTION), STR_SHOW_GUESTS_ON_THIS_RIDE_ATTRACTION_TIP ), MakeWidget({289, 102}, {24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_SHOW_GUESTS_QUEUING_FOR_THIS_RIDE_ATTRACTION), STR_SHOW_GUESTS_QUEUING_FOR_THIS_RIDE_ATTRACTION_TIP ), - kWidgetsEnd, }; - static const std::array PageWidgets = { + static constexpr std::span PageWidgets[] = { _mainWidgets, _vehicleWidgets, _operatingWidgets, @@ -756,11 +746,10 @@ namespace OpenRCT2::Ui::Windows void OnOpen() override { - widgets = PageWidgets[WINDOW_RIDE_PAGE_MAIN]; + SetWidgets(PageWidgets[WINDOW_RIDE_PAGE_MAIN]); hold_down_widgets = PageHoldDownWidgets[WINDOW_RIDE_PAGE_MAIN]; - page = WINDOW_RIDE_PAGE_MAIN; - frame_no = 0; + SetPage(WINDOW_RIDE_PAGE_MAIN); list_information_type = 0; picked_peep_frame = 0; DisableTabs(); @@ -1177,7 +1166,7 @@ namespace OpenRCT2::Ui::Windows hold_down_widgets = PageHoldDownWidgets[page]; pressed_widgets = 0; - widgets = PageWidgets[page]; + SetWidgets(PageWidgets[page]); DisableTabs(); Invalidate(); @@ -1560,7 +1549,7 @@ namespace OpenRCT2::Ui::Windows { _viewIndex = 0; } - if (number < _rideOverallViewsCache.size()) + if (static_cast(number) < _rideOverallViewsCache.size()) { const auto& view = _rideOverallViewsCache[number]; newFocus = Focus(view.loc, view.zoom); @@ -2329,13 +2318,6 @@ namespace OpenRCT2::Ui::Windows { int32_t i, widgetHeight; - auto* newWidgets = PageWidgets[page]; - if (widgets != newWidgets) - { - widgets = newWidgets; - InitScrollWidgets(); - } - SetPressedTab(); auto ride = GetRide(rideId); @@ -2793,13 +2775,6 @@ namespace OpenRCT2::Ui::Windows StringId stringId; int32_t carsPerTrain; - auto* newWidgets = PageWidgets[page]; - if (widgets != newWidgets) - { - widgets = newWidgets; - InitScrollWidgets(); - } - SetPressedTab(); auto ride = GetRide(rideId); @@ -3487,13 +3462,6 @@ namespace OpenRCT2::Ui::Windows { StringId format, caption, tooltip; - auto* newWidgets = PageWidgets[page]; - if (widgets != newWidgets) - { - widgets = newWidgets; - InitScrollWidgets(); - } - SetPressedTab(); auto ride = GetRide(rideId); @@ -4021,13 +3989,6 @@ namespace OpenRCT2::Ui::Windows void MaintenanceOnPrepareDraw() { - auto newWidgets = PageWidgets[page]; - if (widgets != newWidgets) - { - widgets = newWidgets; - InitScrollWidgets(); - } - SetPressedTab(); auto ride = GetRide(rideId); @@ -4604,13 +4565,6 @@ namespace OpenRCT2::Ui::Windows TrackColour trackColour; VehicleColour vehicleColour; - auto newWidgets = PageWidgets[page]; - if (widgets != newWidgets) - { - widgets = newWidgets; - InitScrollWidgets(); - } - SetPressedTab(); auto ride = GetRide(rideId); @@ -5217,13 +5171,6 @@ namespace OpenRCT2::Ui::Windows void MusicOnPrepareDraw() { - auto newWidgets = PageWidgets[page]; - if (widgets != newWidgets) - { - widgets = newWidgets; - InitScrollWidgets(); - } - SetPressedTab(); auto ride = GetRide(rideId); @@ -5613,13 +5560,6 @@ namespace OpenRCT2::Ui::Windows void MeasurementsOnPrepareDraw() { - auto newWidgets = PageWidgets[page]; - if (widgets != newWidgets) - { - widgets = newWidgets; - InitScrollWidgets(); - } - SetPressedTab(); auto ride = GetRide(rideId); @@ -6058,13 +5998,6 @@ namespace OpenRCT2::Ui::Windows void GraphsOnPrepareDraw() { - auto newWidgets = PageWidgets[page]; - if (widgets != newWidgets) - { - widgets = newWidgets; - InitScrollWidgets(); - } - SetPressedTab(); auto ride = GetRide(rideId); @@ -6573,13 +6506,6 @@ namespace OpenRCT2::Ui::Windows void IncomeOnPrepareDraw() { - auto newWidgets = PageWidgets[page]; - if (widgets != newWidgets) - { - widgets = newWidgets; - InitScrollWidgets(); - } - SetPressedTab(); auto ride = GetRide(rideId); @@ -6856,13 +6782,6 @@ namespace OpenRCT2::Ui::Windows void CustomerOnPrepareDraw() { - auto newWidgets = PageWidgets[page]; - if (widgets != newWidgets) - { - widgets = newWidgets; - InitScrollWidgets(); - } - SetPressedTab(); auto ride = GetRide(rideId); diff --git a/src/openrct2-ui/windows/RideConstruction.cpp b/src/openrct2-ui/windows/RideConstruction.cpp index 4e77ccb561..a073404c10 100644 --- a/src/openrct2-ui/windows/RideConstruction.cpp +++ b/src/openrct2-ui/windows/RideConstruction.cpp @@ -142,7 +142,7 @@ namespace OpenRCT2::Ui::Windows validate_global_widx(WC_RIDE_CONSTRUCTION, WIDX_ROTATE); // clang-format off - static Widget _rideConstructionWidgets[] = { + static constexpr Widget _rideConstructionWidgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), MakeWidget ({ 3, 17}, { GW, 57}, WindowWidgetType::Groupbox, WindowColour::Primary , STR_RIDE_CONSTRUCTION_DIRECTION ), MakeWidget ({ 3, 76}, { GW, 41}, WindowWidgetType::Groupbox, WindowColour::Primary , STR_RIDE_CONSTRUCTION_SLOPE ), @@ -179,7 +179,6 @@ namespace OpenRCT2::Ui::Windows MakeWidget ({118, 120}, { 89, 41}, WindowWidgetType::Groupbox, WindowColour::Primary , STR_RIDE_CONSTRUCTION_SEAT_ROT ), MakeSpinnerWidgets({123, 138}, { 58, 12}, WindowWidgetType::Spinner, WindowColour::Secondary, 0, STR_RIDE_CONSTRUCTION_SELECT_SEAT_ROTATION_ANGLE_TIP), MakeWidget ({161, 338}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_G2_SIMULATE), STR_SIMULATE_RIDE_TIP ), - kWidgetsEnd, }; // clang-format on @@ -239,7 +238,7 @@ namespace OpenRCT2::Ui::Windows return; } - widgets = _rideConstructionWidgets; + SetWidgets(_rideConstructionWidgets); number = _currentRideIndex.ToUnderlying(); InitScrollWidgets(); @@ -527,7 +526,7 @@ namespace OpenRCT2::Ui::Windows { case TrackPitch::None: if (_currentlySelectedTrack != TrackCurve::None - || (IsTrackEnabled(TrackGroup::slopeSteepLong) + || (IsTrackEnabled(TrackGroup::slopeSteepLong) && !IsTrackEnabled(TrackGroup::diagSlopeSteepLong) && TrackPieceDirectionIsDiagonal(_currentTrackPieceDirection))) { disabledWidgets |= (1uLL << WIDX_SLOPE_DOWN_STEEP) | (1uLL << WIDX_SLOPE_UP_STEEP); @@ -541,7 +540,9 @@ namespace OpenRCT2::Ui::Windows if (!IsTrackEnabled(TrackGroup::flatToSteepSlope) && !( IsTrackEnabled(TrackGroup::slopeSteepLong) - && !TrackPieceDirectionIsDiagonal(_currentTrackPieceDirection))) + && !( + TrackPieceDirectionIsDiagonal(_currentTrackPieceDirection) + && !IsTrackEnabled(TrackGroup::diagSlopeSteepLong)))) { disabledWidgets |= (1uLL << WIDX_LEVEL); } @@ -554,7 +555,9 @@ namespace OpenRCT2::Ui::Windows if (!IsTrackEnabled(TrackGroup::flatToSteepSlope) && !( IsTrackEnabled(TrackGroup::slopeSteepLong) - && !TrackPieceDirectionIsDiagonal(_currentTrackPieceDirection))) + && !( + TrackPieceDirectionIsDiagonal(_currentTrackPieceDirection) + && !IsTrackEnabled(TrackGroup::diagSlopeSteepLong)))) { disabledWidgets |= (1uLL << WIDX_LEVEL); } @@ -566,7 +569,8 @@ namespace OpenRCT2::Ui::Windows } if (_previousTrackPitchEnd == TrackPitch::None) { - if (!IsTrackEnabled(TrackGroup::flatToSteepSlope) && !IsTrackEnabled(TrackGroup::slopeSteepLong)) + if (!IsTrackEnabled(TrackGroup::flatToSteepSlope) && !IsTrackEnabled(TrackGroup::slopeSteepLong) + && !IsTrackEnabled(TrackGroup::diagSlopeSteepLong)) { disabledWidgets |= (1uLL << WIDX_SLOPE_DOWN_STEEP) | (1uLL << WIDX_SLOPE_UP_STEEP); } @@ -1574,7 +1578,7 @@ namespace OpenRCT2::Ui::Windows currentRide->FormatNameTo(ft); } - static void OnDrawUpdateCoveredPieces(const TrackDrawerDescriptor& trackDrawerDescriptor, Widget* widgets) + static void OnDrawUpdateCoveredPieces(const TrackDrawerDescriptor& trackDrawerDescriptor, std::span widgets) { widgets[WIDX_U_TRACK].type = WindowWidgetType::Empty; widgets[WIDX_O_TRACK].type = WindowWidgetType::Empty; @@ -4929,11 +4933,30 @@ namespace OpenRCT2::Ui::Windows trackType = TrackElemType::Down60ToFlatLongBase; break; + default: + break; + } + } + + if (IsTrackEnabled(TrackGroup::diagSlopeSteepLong)) + { + switch (trackType) + { case TrackElemType::DiagFlatToUp60: + trackType = TrackElemType::DiagFlatToUp60LongBase; + break; + case TrackElemType::DiagUp60ToFlat: + trackType = TrackElemType::DiagUp60ToFlatLongBase; + break; + case TrackElemType::DiagFlatToDown60: + trackType = TrackElemType::DiagFlatToDown60LongBase; + break; + case TrackElemType::DiagDown60ToFlat: - return true; + trackType = TrackElemType::DiagDown60ToFlatLongBase; + break; default: break; diff --git a/src/openrct2-ui/windows/RideList.cpp b/src/openrct2-ui/windows/RideList.cpp index cc185d1615..5d2c49ac9c 100644 --- a/src/openrct2-ui/windows/RideList.cpp +++ b/src/openrct2-ui/windows/RideList.cpp @@ -63,7 +63,7 @@ namespace OpenRCT2::Ui::Windows }; // clang-format off - static Widget _rideListWidgets[] = { + static constexpr Widget _rideListWidgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), MakeWidget({ 0, 43}, {340, 197}, WindowWidgetType::Resize, WindowColour::Secondary ), // tab page background MakeWidget({315, 60}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_TOGGLE_OPEN_CLOSE), STR_OPEN_OR_CLOSE_ALL_RIDES ), // open / close all toggle @@ -77,7 +77,6 @@ namespace OpenRCT2::Ui::Windows MakeWidget({320, 62}, { 14, 14}, WindowWidgetType::ImgBtn, WindowColour::Secondary, ImageId(SPR_G2_RCT1_CLOSE_BUTTON_0) ), MakeWidget({320, 76}, { 14, 14}, WindowWidgetType::ImgBtn, WindowColour::Secondary, ImageId(SPR_G2_RCT1_OPEN_BUTTON_0) ), MakeWidget({315, 90}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_DEMOLISH), STR_QUICK_DEMOLISH_RIDE ), - kWidgetsEnd, }; // clang-format on @@ -174,7 +173,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = _rideListWidgets; + SetWidgets(_rideListWidgets); WindowInitScrollWidgets(*this); page = PAGE_RIDES; selected_list_item = -1; diff --git a/src/openrct2-ui/windows/SavePrompt.cpp b/src/openrct2-ui/windows/SavePrompt.cpp index d1e14b00ae..e454126c35 100644 --- a/src/openrct2-ui/windows/SavePrompt.cpp +++ b/src/openrct2-ui/windows/SavePrompt.cpp @@ -40,13 +40,12 @@ namespace OpenRCT2::Ui::Windows }; // clang-format off - static Widget _savePromptWidgets[] = { + static constexpr Widget _savePromptWidgets[] = { WINDOW_SHIM_WHITE(STR_NONE, WW_SAVE, WH_SAVE), MakeWidget({ 2, 19}, {256, 12}, WindowWidgetType::LabelCentred, WindowColour::Primary, STR_EMPTY ), // question/label MakeWidget({ 8, 35}, { 78, 14}, WindowWidgetType::Button, WindowColour::Primary, STR_SAVE_PROMPT_SAVE ), // save MakeWidget({ 91, 35}, { 78, 14}, WindowWidgetType::Button, WindowColour::Primary, STR_SAVE_PROMPT_DONT_SAVE), // don't save MakeWidget({174, 35}, { 78, 14}, WindowWidgetType::Button, WindowColour::Primary, STR_SAVE_PROMPT_CANCEL ), // cancel - kWidgetsEnd, }; // clang-format on @@ -60,11 +59,10 @@ namespace OpenRCT2::Ui::Windows }; // clang-format off - static Widget _quitPromptWidgets[] = { + static constexpr Widget _quitPromptWidgets[] = { WINDOW_SHIM_WHITE(STR_QUIT_GAME_PROMPT_TITLE, WW_QUIT, WH_QUIT), MakeWidget({ 8, 19}, {78, 14}, WindowWidgetType::Button, WindowColour::Primary, STR_OK ), // ok MakeWidget({91, 19}, {78, 14}, WindowWidgetType::Button, WindowColour::Primary, STR_CANCEL), // cancel - kWidgetsEnd, }; // clang-format on @@ -98,7 +96,10 @@ namespace OpenRCT2::Ui::Windows { bool canSave = !(gScreenFlags & (SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER)); - widgets = canSave ? _savePromptWidgets : _quitPromptWidgets; + if (canSave) + SetWidgets(_savePromptWidgets); + else + SetWidgets(_quitPromptWidgets); InitScrollWidgets(); diff --git a/src/openrct2-ui/windows/ScenarioSelect.cpp b/src/openrct2-ui/windows/ScenarioSelect.cpp index 1fb8d17359..65003c5362 100644 --- a/src/openrct2-ui/windows/ScenarioSelect.cpp +++ b/src/openrct2-ui/windows/ScenarioSelect.cpp @@ -92,7 +92,7 @@ namespace OpenRCT2::Ui::Windows }; // clang-format off - static Widget _scenarioSelectWidgets[] = { + static constexpr Widget _scenarioSelectWidgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), MakeWidget({ TabWidth + 1, WidgetsStart }, { WW, 284 }, WindowWidgetType::Resize, WindowColour::Secondary), // tab content panel MakeRemapWidget({ 3, TabsStart + (TabHeight * 0) }, { TabWidth, TabHeight}, WindowWidgetType::Tab, WindowColour::Secondary, SPR_G2_SIDEWAYS_TAB), // tab 01 @@ -106,7 +106,6 @@ namespace OpenRCT2::Ui::Windows MakeRemapWidget({ 3, TabsStart + (TabHeight * 8) }, { TabWidth, TabHeight}, WindowWidgetType::Tab, WindowColour::Secondary, SPR_G2_SIDEWAYS_TAB), // tab 09 MakeRemapWidget({ 3, TabsStart + (TabHeight * 8) }, { TabWidth, TabHeight}, WindowWidgetType::Tab, WindowColour::Secondary, SPR_G2_SIDEWAYS_TAB), // tab 10 MakeWidget({ TabWidth + 3, WidgetsStart + 1 }, { WW - SidebarWidth, 362 }, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_VERTICAL), // level list - kWidgetsEnd, }; // clang-format on @@ -126,7 +125,7 @@ namespace OpenRCT2::Ui::Windows void OnOpen() override { - widgets = _scenarioSelectWidgets; + SetWidgets(_scenarioSelectWidgets); // Load scenario list ScenarioRepositoryScan(); diff --git a/src/openrct2-ui/windows/Scenery.cpp b/src/openrct2-ui/windows/Scenery.cpp index ab34c1244a..73730c0195 100644 --- a/src/openrct2-ui/windows/Scenery.cpp +++ b/src/openrct2-ui/windows/Scenery.cpp @@ -108,7 +108,7 @@ namespace OpenRCT2::Ui::Windows validate_global_widx(WC_SCENERY, WIDX_SCENERY_EYEDROPPER_BUTTON); // clang-format off - static Widget WindowSceneryBaseWidgets[] = { + static constexpr Widget WindowSceneryBaseWidgets[] = { WINDOW_SHIM(WINDOW_TITLE, WINDOW_SCENERY_MIN_WIDTH, WINDOW_SCENERY_MIN_HEIGHT), MakeWidget ({ 0, 43}, {634, 99}, WindowWidgetType::Resize, WindowColour::Secondary ), // 8 0x009DE2C8 MakeWidget ({ 2, 62}, {607, 80}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_VERTICAL ), // 1000000 0x009DE418 @@ -122,7 +122,6 @@ namespace OpenRCT2::Ui::Windows MakeWidget ({ 4, 46}, {211, 14}, WindowWidgetType::TextBox, WindowColour::Secondary ), MakeWidget ({218, 46}, { 70, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_OBJECT_SEARCH_CLEAR ), MakeWidget ({539, 46}, { 70, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_RESTRICT_SCENERY, STR_RESTRICT_SCENERY_TIP ), - kWidgetsEnd, }; // clang-format on @@ -205,7 +204,6 @@ namespace OpenRCT2::Ui::Windows }; std::vector _tabEntries; - std::vector _widgets; int32_t _requiredWidth; int32_t _actualMinHeight; ScenerySelection _selectedScenery; @@ -1362,15 +1360,7 @@ namespace OpenRCT2::Ui::Windows void PrepareWidgets() { // Add the base widgets - _widgets.clear(); - for (const auto& widget : WindowSceneryBaseWidgets) - { - _widgets.push_back(widget); - } - - // Remove WWT_LAST - auto lastWidget = _widgets.back(); - _widgets.pop_back(); + SetWidgets(WindowSceneryBaseWidgets); // Add tabs _actualMinHeight = WINDOW_SCENERY_MIN_HEIGHT; @@ -1407,7 +1397,7 @@ namespace OpenRCT2::Ui::Windows } } - _widgets.push_back(widget); + widgets.push_back(widget); tabsInThisRow++; if (tabsInThisRow >= maxTabsInThisRow) @@ -1420,35 +1410,31 @@ namespace OpenRCT2::Ui::Windows } } - _widgets.push_back(lastWidget); - // Shift base widgets based on number of tab rows int32_t shiftAmount = (GetTabRowCount() - 1) * TabHeight; if (shiftAmount > 0) { - _widgets[WIDX_SCENERY_LIST].top += shiftAmount; - _widgets[WIDX_SCENERY_LIST].bottom += shiftAmount; - _widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].top += shiftAmount; - _widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].bottom += shiftAmount; - _widgets[WIDX_SCENERY_REPAINT_SCENERY_BUTTON].top += shiftAmount; - _widgets[WIDX_SCENERY_REPAINT_SCENERY_BUTTON].bottom += shiftAmount; - _widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].top += shiftAmount; - _widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].bottom += shiftAmount; - _widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].top += shiftAmount; - _widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].bottom += shiftAmount; - _widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].top += shiftAmount; - _widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].bottom += shiftAmount; - _widgets[WIDX_SCENERY_EYEDROPPER_BUTTON].top += shiftAmount; - _widgets[WIDX_SCENERY_EYEDROPPER_BUTTON].bottom += shiftAmount; - _widgets[WIDX_SCENERY_BUILD_CLUSTER_BUTTON].top += shiftAmount; - _widgets[WIDX_SCENERY_BUILD_CLUSTER_BUTTON].bottom += shiftAmount; - _widgets[WIDX_FILTER_TEXT_BOX].top += shiftAmount; - _widgets[WIDX_FILTER_TEXT_BOX].bottom += shiftAmount; - _widgets[WIDX_FILTER_CLEAR_BUTTON].top += shiftAmount; - _widgets[WIDX_FILTER_CLEAR_BUTTON].bottom += shiftAmount; + widgets[WIDX_SCENERY_LIST].top += shiftAmount; + widgets[WIDX_SCENERY_LIST].bottom += shiftAmount; + widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].top += shiftAmount; + widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].bottom += shiftAmount; + widgets[WIDX_SCENERY_REPAINT_SCENERY_BUTTON].top += shiftAmount; + widgets[WIDX_SCENERY_REPAINT_SCENERY_BUTTON].bottom += shiftAmount; + widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].top += shiftAmount; + widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].bottom += shiftAmount; + widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].top += shiftAmount; + widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].bottom += shiftAmount; + widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].top += shiftAmount; + widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].bottom += shiftAmount; + widgets[WIDX_SCENERY_EYEDROPPER_BUTTON].top += shiftAmount; + widgets[WIDX_SCENERY_EYEDROPPER_BUTTON].bottom += shiftAmount; + widgets[WIDX_SCENERY_BUILD_CLUSTER_BUTTON].top += shiftAmount; + widgets[WIDX_SCENERY_BUILD_CLUSTER_BUTTON].bottom += shiftAmount; + widgets[WIDX_FILTER_TEXT_BOX].top += shiftAmount; + widgets[WIDX_FILTER_TEXT_BOX].bottom += shiftAmount; + widgets[WIDX_FILTER_CLEAR_BUTTON].top += shiftAmount; + widgets[WIDX_FILTER_CLEAR_BUTTON].bottom += shiftAmount; } - - widgets = _widgets.data(); } ScenerySelection GetSceneryIdByCursorPos(const ScreenCoordsXY& screenCoords) const diff --git a/src/openrct2-ui/windows/SceneryScatter.cpp b/src/openrct2-ui/windows/SceneryScatter.cpp index 8f4ce306ca..57a10df675 100644 --- a/src/openrct2-ui/windows/SceneryScatter.cpp +++ b/src/openrct2-ui/windows/SceneryScatter.cpp @@ -40,7 +40,7 @@ namespace OpenRCT2::Ui::Windows ScatterToolDensity gWindowSceneryScatterDensity; // clang-format off - static Widget _sceneryScatterWidgets[] = { + static constexpr Widget _sceneryScatterWidgets[] = { MakeWidget ({ 0, 0}, {86, 100}, WindowWidgetType::Frame, WindowColour::Secondary ), // panel / background MakeWidget ({ 1, 1}, {84, 14}, WindowWidgetType::Caption, WindowColour::Primary , STR_SCENERY_SCATTER, STR_WINDOW_TITLE_TIP ), // title bar MakeWidget ({73, 2}, {11, 12}, WindowWidgetType::CloseBox, WindowColour::Primary , STR_CLOSE_X, STR_CLOSE_WINDOW_TIP ), // close x button @@ -53,7 +53,6 @@ namespace OpenRCT2::Ui::Windows MakeRemapWidget({ 7, 68}, {24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_G2_SCENERY_SCATTER_LOW, STR_SCATTER_TOOL_DENSITY_LOW ), // low amount MakeRemapWidget({31, 68}, {24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_G2_SCENERY_SCATTER_MEDIUM, STR_SCATTER_TOOL_DENSITY_MEDIUM), // medium amount MakeRemapWidget({55, 68}, {24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_G2_SCENERY_SCATTER_HIGH, STR_SCATTER_TOOL_DENSITY_HIGH ), // high amount - kWidgetsEnd, }; // clang-format on @@ -62,7 +61,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = _sceneryScatterWidgets; + SetWidgets(_sceneryScatterWidgets); hold_down_widgets = (1uLL << WIDX_INCREMENT) | (1uLL << WIDX_DECREMENT); WindowInitScrollWidgets(*this); WindowPushOthersBelow(*this); diff --git a/src/openrct2-ui/windows/ServerList.cpp b/src/openrct2-ui/windows/ServerList.cpp index 8b5ca04d61..0a2789fb23 100644 --- a/src/openrct2-ui/windows/ServerList.cpp +++ b/src/openrct2-ui/windows/ServerList.cpp @@ -62,7 +62,7 @@ namespace OpenRCT2::Ui::Windows }; // clang-format off - static Widget _serverListWidgets[] = { + static constexpr Widget _serverListWidgets[] = { MakeWidget({ 0, 0}, {341, 91}, WindowWidgetType::Frame, WindowColour::Primary ), // panel / background MakeWidget({ 1, 1}, {338, 14}, WindowWidgetType::Caption, WindowColour::Primary, STR_SERVER_LIST, STR_WINDOW_TITLE_TIP), // title bar MakeWidget({327, 2}, { 11, 12}, WindowWidgetType::CloseBox, WindowColour::Primary, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP), // close x button @@ -71,7 +71,6 @@ namespace OpenRCT2::Ui::Windows MakeWidget({ 6, 53}, {101, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_FETCH_SERVERS ), // fetch servers button MakeWidget({112, 53}, {101, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_ADD_SERVER ), // add server button MakeWidget({218, 53}, {101, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_START_SERVER ), // start server button - kWidgetsEnd, }; // clang-format on @@ -95,8 +94,8 @@ namespace OpenRCT2::Ui::Windows void OnOpen() override { _playerName = Config::Get().network.PlayerName; - widgets = _serverListWidgets; - _serverListWidgets[WIDX_PLAYER_NAME_INPUT].string = const_cast(_playerName.c_str()); + SetWidgets(_serverListWidgets); + widgets[WIDX_PLAYER_NAME_INPUT].string = const_cast(_playerName.c_str()); InitScrollWidgets(); no_list_items = 0; selected_list_item = -1; diff --git a/src/openrct2-ui/windows/ServerStart.cpp b/src/openrct2-ui/windows/ServerStart.cpp index 1f538b7c3f..0c966df47c 100644 --- a/src/openrct2-ui/windows/ServerStart.cpp +++ b/src/openrct2-ui/windows/ServerStart.cpp @@ -45,7 +45,7 @@ namespace OpenRCT2::Ui::Windows static constexpr int32_t WH = 154; // clang-format off - static Widget _windowServerStartWidgets[] = { + static constexpr Widget _windowServerStartWidgets[] = { MakeWidget({ 0, 0 }, { WW, WH }, WindowWidgetType::Frame, WindowColour::Primary), // panel / background MakeWidget({ 1, 1 }, { 298, 14 }, WindowWidgetType::Caption, WindowColour::Primary, STR_START_SERVER,STR_WINDOW_TITLE_TIP), // title bar MakeWidget({ WW - 13, 2 }, { 11, 12 }, WindowWidgetType::CloseBox, WindowColour::Primary, STR_CLOSE_X,STR_CLOSE_WINDOW_TIP), // close x button @@ -58,7 +58,6 @@ namespace OpenRCT2::Ui::Windows MakeWidget({ 6, 117 }, { 287, 14 }, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_ADVERTISE,STR_ADVERTISE_SERVER_TIP), // advertise checkbox MakeWidget({ 6, WH - 6 - 13 }, { 101, 14 }, WindowWidgetType::Button, WindowColour::Secondary,STR_NEW_GAME), // start server button MakeWidget({ 112, WH - 6 - 13 }, { 101, 14 }, WindowWidgetType::Button, WindowColour::Secondary, STR_LOAD_GAME), // None - kWidgetsEnd, }; // clang-format on @@ -67,7 +66,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = _windowServerStartWidgets; + SetWidgets(_windowServerStartWidgets); widgets[WIDX_PORT_INPUT].string = _port; widgets[WIDX_NAME_INPUT].string = _name; widgets[WIDX_DESCRIPTION_INPUT].string = _description; diff --git a/src/openrct2-ui/windows/ShortcutKeys.cpp b/src/openrct2-ui/windows/ShortcutKeys.cpp index 2cb9d2a6ee..9b079d8c5c 100644 --- a/src/openrct2-ui/windows/ShortcutKeys.cpp +++ b/src/openrct2-ui/windows/ShortcutKeys.cpp @@ -43,12 +43,11 @@ namespace OpenRCT2::Ui::Windows }; // clang-format off - static Widget _shortcutWidgets[] = { + static constexpr Widget _shortcutWidgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), MakeWidget({0, 43}, {350, 287}, WindowWidgetType::Resize, WindowColour::Secondary), MakeWidget({4, 47}, {412, 215}, WindowWidgetType::Scroll, WindowColour::Primary, SCROLL_VERTICAL, STR_SHORTCUT_LIST_TIP ), MakeWidget({4, WH-15}, {150, 12}, WindowWidgetType::Button, WindowColour::Primary, STR_SHORTCUT_ACTION_RESET, STR_SHORTCUT_ACTION_RESET_TIP), - kWidgetsEnd, }; // clang-format on @@ -62,10 +61,9 @@ namespace OpenRCT2::Ui::Windows }; // clang-format off - static Widget window_shortcut_change_widgets[] = { + static constexpr Widget window_shortcut_change_widgets[] = { WINDOW_SHIM(CHANGE_WINDOW_TITLE, CHANGE_WW, CHANGE_WH), MakeWidget({ 75, 56 }, { 100, 14 }, WindowWidgetType::Button, WindowColour::Primary, STR_SHORTCUT_REMOVE, STR_SHORTCUT_REMOVE_TIP), - kWidgetsEnd, }; // clang-format on @@ -100,7 +98,7 @@ namespace OpenRCT2::Ui::Windows void OnOpen() override { - widgets = window_shortcut_change_widgets; + SetWidgets(window_shortcut_change_widgets); WindowInitScrollWidgets(*this); } @@ -450,20 +448,17 @@ namespace OpenRCT2::Ui::Windows void InitialiseWidgets() { - _widgets.clear(); - _widgets.insert(_widgets.begin(), std::begin(_shortcutWidgets), std::end(_shortcutWidgets) - 1); + widgets.clear(); + widgets.insert(widgets.begin(), std::begin(_shortcutWidgets), std::end(_shortcutWidgets) - 1); int32_t x = 3; for (size_t i = 0; i < _tabs.size(); i++) { auto tab = MakeTab({ x, 17 }, STR_NONE); - _widgets.push_back(tab); + widgets.push_back(tab); x += 31; } - _widgets.push_back(kWidgetsEnd); - widgets = _widgets.data(); - WindowInitScrollWidgets(*this); } @@ -581,7 +576,7 @@ namespace OpenRCT2::Ui::Windows WIDX_RESET_PROMPT_CANCEL }; - static Widget WindowResetShortcutKeysPromptWidgets[] = { + static constexpr Widget WindowResetShortcutKeysPromptWidgets[] = { WINDOW_SHIM_WHITE(STR_SHORTCUT_ACTION_RESET, RESET_PROMPT_WW, RESET_PROMPT_WH), MakeWidget( { 2, 30 }, { RESET_PROMPT_WW - 4, 12 }, WindowWidgetType::LabelCentred, WindowColour::Primary, @@ -590,14 +585,13 @@ namespace OpenRCT2::Ui::Windows MakeWidget( { RESET_PROMPT_WW - 95, RESET_PROMPT_WH - 22 }, { 85, 14 }, WindowWidgetType::Button, WindowColour::Primary, STR_SAVE_PROMPT_CANCEL), - kWidgetsEnd, }; class ResetShortcutKeysPrompt final : public Window { void OnOpen() override { - widgets = WindowResetShortcutKeysPromptWidgets; + SetWidgets(WindowResetShortcutKeysPromptWidgets); } void OnMouseUp(WidgetIndex widgetIndex) override diff --git a/src/openrct2-ui/windows/Sign.cpp b/src/openrct2-ui/windows/Sign.cpp index 6c51039545..3f3bf92f19 100644 --- a/src/openrct2-ui/windows/Sign.cpp +++ b/src/openrct2-ui/windows/Sign.cpp @@ -48,14 +48,13 @@ namespace OpenRCT2::Ui::Windows // clang-format off // 0x9AEE00 - static Widget _signWidgets[] = { + static constexpr Widget _signWidgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), MakeWidget({ 3, 17}, {85, 60}, WindowWidgetType::Viewport, WindowColour::Secondary ), // Viewport MakeWidget({WW - 25, 19}, {24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_RENAME), STR_CHANGE_SIGN_TEXT_TIP ), // change sign button MakeWidget({WW - 25, 67}, {24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_DEMOLISH), STR_DEMOLISH_SIGN_TIP ), // demolish button MakeWidget({ 5, WH - 16}, {12, 12}, WindowWidgetType::ColourBtn, WindowColour::Secondary, kWidgetContentEmpty, STR_SELECT_MAIN_SIGN_COLOUR_TIP), // Main colour MakeWidget({ 17, WH - 16}, {12, 12}, WindowWidgetType::ColourBtn, WindowColour::Secondary, kWidgetContentEmpty, STR_SELECT_TEXT_COLOUR_TIP ), // Text colour - kWidgetsEnd, }; // clang-format on @@ -86,7 +85,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = _signWidgets; + SetWidgets(_signWidgets); WindowInitScrollWidgets(*this); } diff --git a/src/openrct2-ui/windows/Staff.cpp b/src/openrct2-ui/windows/Staff.cpp index 7a82fd97a8..eed00969f7 100644 --- a/src/openrct2-ui/windows/Staff.cpp +++ b/src/openrct2-ui/windows/Staff.cpp @@ -93,7 +93,7 @@ namespace OpenRCT2::Ui::Windows MakeTab({ 65, 17 }, STR_STAFF_STATS_TIP) /* Tab 3 */ // clang-format off - static Widget _staffOverviewWidgets[] = { + static constexpr Widget _staffOverviewWidgets[] = { MAIN_STAFF_WIDGETS, MakeWidget ({ 3, 47}, {162, 120}, WindowWidgetType::Viewport, WindowColour::Secondary ), // Viewport MakeWidget ({ 3, WH - 13}, {162, 11}, WindowWidgetType::LabelCentred, WindowColour::Secondary ), // Label at bottom of viewport @@ -102,11 +102,10 @@ namespace OpenRCT2::Ui::Windows MakeWidget ({WW - 25, 93}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_RENAME), STR_NAME_STAFF_TIP ), // Rename Button MakeWidget ({WW - 25, 117}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_LOCATE), STR_LOCATE_SUBJECT_TIP), // Locate Button MakeWidget ({WW - 25, 141}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_DEMOLISH), STR_FIRE_STAFF_TIP ), // Fire Button - kWidgetsEnd, }; //0x9AF910 - static Widget _staffOptionsWidgets[] = { + static constexpr Widget _staffOptionsWidgets[] = { MAIN_STAFF_WIDGETS, MakeWidget ({ 5, 50}, {180, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary ), // Checkbox 1 MakeWidget ({ 5, 67}, {180, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary ), // Checkbox 2 @@ -114,17 +113,15 @@ namespace OpenRCT2::Ui::Windows MakeWidget ({ 5, 101}, {180, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary ), // Checkbox 4 MakeWidget ({ 5, 50}, {180, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary ), // Costume Dropdown MakeWidget ({WW - 17, 51}, { 11, 10}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH, STR_SELECT_COSTUME_TIP), // Costume Dropdown Button - kWidgetsEnd, }; // clang-format on // 0x9AF9F4 - static Widget _staffStatsWidgets[] = { + static constexpr Widget _staffStatsWidgets[] = { MAIN_STAFF_WIDGETS, - kWidgetsEnd, }; - static Widget* window_staff_page_widgets[] = { + static constexpr std::span window_staff_page_widgets[] = { _staffOverviewWidgets, _staffOptionsWidgets, _staffStatsWidgets, @@ -341,11 +338,6 @@ namespace OpenRCT2::Ui::Windows { ColourSchemeUpdateByClass(this, static_cast(WindowClass::Staff)); - if (window_staff_page_widgets[page] != widgets) - { - widgets = window_staff_page_widgets[page]; - InitScrollWidgets(); - } SetPressedTab(); DisableWidgets(); @@ -1086,7 +1078,7 @@ namespace OpenRCT2::Ui::Windows return; } - for (WidgetIndex widgetIndex = WIDX_TAB_1; widgets[widgetIndex].type != kWidgetsEnd.type; widgetIndex++) + for (WidgetIndex widgetIndex = WIDX_TAB_1; widgetIndex < widgets.size(); widgetIndex++) { SetWidgetDisabled(widgetIndex, false); } @@ -1132,7 +1124,7 @@ namespace OpenRCT2::Ui::Windows frame_no = 0; pressed_widgets = 0; hold_down_widgets = 0; - widgets = window_staff_page_widgets[page]; + SetWidgets(window_staff_page_widgets[page]); RemoveViewport(); diff --git a/src/openrct2-ui/windows/StaffFirePrompt.cpp b/src/openrct2-ui/windows/StaffFirePrompt.cpp index d903ca9111..3b24b3b7a2 100644 --- a/src/openrct2-ui/windows/StaffFirePrompt.cpp +++ b/src/openrct2-ui/windows/StaffFirePrompt.cpp @@ -34,11 +34,10 @@ namespace OpenRCT2::Ui::Windows // clang-format off // 0x9AFB4C - static Widget _staffFireWidgets[] = { + static constexpr Widget _staffFireWidgets[] = { WINDOW_SHIM_WHITE(WINDOW_TITLE, WW, WH), MakeWidget({ 10, WH - 20}, {85, 14}, WindowWidgetType::Button, WindowColour::Primary, STR_YES ), MakeWidget({WW - 95, WH - 20}, {85, 14}, WindowWidgetType::Button, WindowColour::Primary, STR_SAVE_PROMPT_CANCEL), - kWidgetsEnd, }; // clang-format on @@ -52,7 +51,7 @@ namespace OpenRCT2::Ui::Windows void OnOpen() override { - widgets = _staffFireWidgets; + SetWidgets(_staffFireWidgets); WindowInitScrollWidgets(*this); } diff --git a/src/openrct2-ui/windows/StaffList.cpp b/src/openrct2-ui/windows/StaffList.cpp index e1f8cd013d..24928e529b 100644 --- a/src/openrct2-ui/windows/StaffList.cpp +++ b/src/openrct2-ui/windows/StaffList.cpp @@ -80,7 +80,7 @@ namespace OpenRCT2::Ui::Windows constexpr int32_t MAX_WH = 450; // clang-format off - static Widget _staffListWidgets[] = { + static constexpr Widget _staffListWidgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), MakeWidget({ 0, 43}, { WW, WH - 43}, WindowWidgetType::Resize, WindowColour::Secondary ), // tab content panel MakeTab ({ 3, 17}, STR_STAFF_HANDYMEN_TAB_TIP ), // handymen tab @@ -93,7 +93,6 @@ namespace OpenRCT2::Ui::Windows MakeWidget({243, 46}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_DEMOLISH), STR_QUICK_FIRE_STAFF ), // quick fire staff MakeWidget({267, 46}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_PATROL_BTN), STR_SHOW_PATROL_AREA_TIP ), // show staff patrol area tool MakeWidget({291, 46}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_MAP), STR_SHOW_STAFF_ON_MAP_TIP), // show staff on map button - kWidgetsEnd, }; // clang-format on @@ -122,7 +121,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = _staffListWidgets; + SetWidgets(_staffListWidgets); WindowInitScrollWidgets(*this); widgets[WIDX_STAFF_LIST_UNIFORM_COLOUR_PICKER].type = WindowWidgetType::Empty; diff --git a/src/openrct2-ui/windows/TextInput.cpp b/src/openrct2-ui/windows/TextInput.cpp index ec9521f3bb..79db7aef42 100644 --- a/src/openrct2-ui/windows/TextInput.cpp +++ b/src/openrct2-ui/windows/TextInput.cpp @@ -35,11 +35,10 @@ namespace OpenRCT2::Ui::Windows WIDX_OKAY }; - static Widget _textInputWidgets[] = { + static constexpr Widget _textInputWidgets[] = { WINDOW_SHIM(STR_NONE, WW, WH), MakeWidget({ 170, 68 }, { 71, 14 }, WindowWidgetType::Button, WindowColour::Secondary, STR_CANCEL), MakeWidget({ 10, 68 }, { 71, 14 }, WindowWidgetType::Button, WindowColour::Secondary, STR_OK), - kWidgetsEnd, }; class TextInputWindow final : public Window @@ -64,7 +63,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = _textInputWidgets; + SetWidgets(_textInputWidgets); WindowInitScrollWidgets(*this); SetParentWindow(nullptr, 0); } diff --git a/src/openrct2-ui/windows/Themes.cpp b/src/openrct2-ui/windows/Themes.cpp index 7274d95db6..05a5c1e849 100644 --- a/src/openrct2-ui/windows/Themes.cpp +++ b/src/openrct2-ui/windows/Themes.cpp @@ -78,7 +78,7 @@ namespace OpenRCT2::Ui::Windows const uint16_t kWindowHeaderWidth = 152; // clang-format off - static Widget _themesWidgets[] = { + static constexpr Widget _themesWidgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), MakeWidget({ 0, 43}, {320, 64}, WindowWidgetType::Resize, WindowColour::Secondary ), // tab content panel MakeTab ({ 3, 17}, STR_THEMES_TAB_SETTINGS_TIP ), // settings tab @@ -104,7 +104,6 @@ namespace OpenRCT2::Ui::Windows MakeWidget({ 10, 69}, {290, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_THEMES_OPTION_RCT1_PARK_CONTROLS ), // rct1 park lights MakeWidget({ 10, 84}, {290, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_THEMES_OPTION_RCT1_SCENARIO_SELECTION_FONT ), // rct1 scenario font MakeWidget({ 10, 99}, {290, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_THEMES_OPTION_RCT1_BOTTOM_TOOLBAR ), // rct1 bottom toolbar - kWidgetsEnd, }; // clang-format on @@ -265,7 +264,7 @@ namespace OpenRCT2::Ui::Windows void OnOpen() override { - widgets = _themesWidgets; + SetWidgets(_themesWidgets); WindowThemesInitVars(); diff --git a/src/openrct2-ui/windows/TileInspector.cpp b/src/openrct2-ui/windows/TileInspector.cpp index cb705a3800..04b5faaae8 100644 --- a/src/openrct2-ui/windows/TileInspector.cpp +++ b/src/openrct2-ui/windows/TileInspector.cpp @@ -199,6 +199,22 @@ namespace OpenRCT2::Ui::Windows static_assert(WC_TILE_INSPECTOR__WIDX_SPINNER_X_DECREASE == WIDX_SPINNER_X_DECREASE); static_assert(WC_TILE_INSPECTOR__WIDX_SPINNER_Y_INCREASE == WIDX_SPINNER_Y_INCREASE); static_assert(WC_TILE_INSPECTOR__WIDX_SPINNER_Y_DECREASE == WIDX_SPINNER_Y_DECREASE); + static_assert(WC_TILE_INSPECTOR__WIDX_SURFACE_SPINNER_HEIGHT_INCREASE == WIDX_SURFACE_SPINNER_HEIGHT_INCREASE); + static_assert(WC_TILE_INSPECTOR__WIDX_SURFACE_SPINNER_HEIGHT_DECREASE == WIDX_SURFACE_SPINNER_HEIGHT_DECREASE); + static_assert(WC_TILE_INSPECTOR__WIDX_PATH_SPINNER_HEIGHT_INCREASE == WIDX_PATH_SPINNER_HEIGHT_INCREASE); + static_assert(WC_TILE_INSPECTOR__WIDX_PATH_SPINNER_HEIGHT_DECREASE == WIDX_PATH_SPINNER_HEIGHT_DECREASE); + static_assert(WC_TILE_INSPECTOR__WIDX_TRACK_SPINNER_HEIGHT_INCREASE == WIDX_TRACK_SPINNER_HEIGHT_INCREASE); + static_assert(WC_TILE_INSPECTOR__WIDX_TRACK_SPINNER_HEIGHT_DECREASE == WIDX_TRACK_SPINNER_HEIGHT_DECREASE); + static_assert(WC_TILE_INSPECTOR__WIDX_SCENERY_SPINNER_HEIGHT_INCREASE == WIDX_SCENERY_SPINNER_HEIGHT_INCREASE); + static_assert(WC_TILE_INSPECTOR__WIDX_SCENERY_SPINNER_HEIGHT_DECREASE == WIDX_SCENERY_SPINNER_HEIGHT_DECREASE); + static_assert(WC_TILE_INSPECTOR__WIDX_ENTRANCE_SPINNER_HEIGHT_INCREASE == WIDX_ENTRANCE_SPINNER_HEIGHT_INCREASE); + static_assert(WC_TILE_INSPECTOR__WIDX_ENTRANCE_SPINNER_HEIGHT_DECREASE == WIDX_ENTRANCE_SPINNER_HEIGHT_DECREASE); + static_assert(WC_TILE_INSPECTOR__WIDX_WALL_SPINNER_HEIGHT_INCREASE == WIDX_WALL_SPINNER_HEIGHT_INCREASE); + static_assert(WC_TILE_INSPECTOR__WIDX_WALL_SPINNER_HEIGHT_DECREASE == WIDX_WALL_SPINNER_HEIGHT_DECREASE); + static_assert(WC_TILE_INSPECTOR__WIDX_LARGE_SCENERY_SPINNER_HEIGHT_INCREASE == WIDX_LARGE_SCENERY_SPINNER_HEIGHT_INCREASE); + static_assert(WC_TILE_INSPECTOR__WIDX_LARGE_SCENERY_SPINNER_HEIGHT_DECREASE == WIDX_LARGE_SCENERY_SPINNER_HEIGHT_DECREASE); + static_assert(WC_TILE_INSPECTOR__WIDX_BANNER_SPINNER_HEIGHT_INCREASE == WIDX_BANNER_SPINNER_HEIGHT_INCREASE); + static_assert(WC_TILE_INSPECTOR__WIDX_BANNER_SPINNER_HEIGHT_DECREASE == WIDX_BANNER_SPINNER_HEIGHT_DECREASE); #pragma region MEASUREMENTS @@ -289,16 +305,15 @@ namespace OpenRCT2::Ui::Windows MakeWidget({6, 0}, {WW - 12, 0}, WindowWidgetType::Groupbox, WindowColour::Secondary, STR_NONE, STR_NONE ), /* Details group box */ \ MakeWidget({6, 0}, {WW - 12, 0}, WindowWidgetType::Groupbox, WindowColour::Secondary, STR_TILE_INSPECTOR_GROUPBOX_PROPERTIES, STR_NONE ) /* Properties group box */ - static Widget DefaultWidgets[] = { + static constexpr Widget DefaultWidgets[] = { MAIN_TILE_INSPECTOR_WIDGETS, - kWidgetsEnd, }; constexpr int32_t NumSurfaceProperties = 4; constexpr int32_t NumSurfaceDetails = 4; constexpr int32_t SurfacePropertiesHeight = 16 + NumSurfaceProperties * 21; constexpr int32_t SurfaceDetailsHeight = 20 + NumSurfaceDetails * 11; - static Widget SurfaceWidgets[] = { + static constexpr Widget SurfaceWidgets[] = { MAIN_TILE_INSPECTOR_WIDGETS, MakeSpinnerWidgets(PropertyRowCol({ 12, 0 }, 0, 1), PropertyButtonSize, WindowWidgetType::Spinner, WindowColour::Secondary), // WIDX_SURFACE_SPINNER_HEIGHT{,_INCREASE,_DECREASE} MakeWidget(PropertyRowCol({ 12, 0 }, 1, 0), PropertyButtonSize, WindowWidgetType::Button, WindowColour::Secondary, STR_TILE_INSPECTOR_SURFACE_REMOVE_FENCES), // WIDX_SURFACE_BUTTON_REMOVE_FENCES @@ -308,14 +323,13 @@ namespace OpenRCT2::Ui::Windows MakeWidget(CheckboxGroupOffset(PropertyRowCol({ 12, 0 }, 3, 1), 1, 2), { 12, 12 }, WindowWidgetType::Checkbox, WindowColour::Secondary), // WIDX_SURFACE_CHECK_CORNER_S MakeWidget(CheckboxGroupOffset(PropertyRowCol({ 12, 0 }, 3, 1), 0, 1), { 12, 12 }, WindowWidgetType::Checkbox, WindowColour::Secondary), // WIDX_SURFACE_CHECK_CORNER_W MakeWidget(PropertyRowCol({ 12, 0 }, 4, 0), PropertyFullWidth, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_TILE_INSPECTOR_SURFACE_DIAGONAL), // WIDX_SURFACE_CHECK_DIAGONAL - kWidgetsEnd, }; constexpr int32_t NumPathProperties = 6; constexpr int32_t NumPathDetails = 3; constexpr int32_t PathPropertiesHeight = 16 + NumPathProperties * 21; constexpr int32_t PathDetailsHeight = 20 + NumPathDetails * 11; - static Widget PathWidgets[] = { + static constexpr Widget PathWidgets[] = { MAIN_TILE_INSPECTOR_WIDGETS, MakeSpinnerWidgets(PropertyRowCol({ 12, 0 }, 0, 1), PropertyButtonSize, WindowWidgetType::Spinner, WindowColour::Secondary), // WIDX_PATH_SPINNER_HEIGHT{,_INCREASE,_DECREASE} MakeWidget(PropertyRowCol({ 12, 0 }, 1, 0), PropertyFullWidth, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_TILE_INSPECTOR_PATH_BROKEN), // WIDX_PATH_CHECK_BROKEN @@ -329,28 +343,26 @@ namespace OpenRCT2::Ui::Windows MakeWidget(CheckboxGroupOffset(PropertyRowCol({ 12, 0 }, 4, 1), 0, 2), { 12, 12 }, WindowWidgetType::Checkbox, WindowColour::Secondary), // WIDX_PATH_CHECK_EDGE_W MakeWidget(CheckboxGroupOffset(PropertyRowCol({ 12, 0 }, 4, 1), 1, 1), { 12, 12 }, WindowWidgetType::Checkbox, WindowColour::Secondary), // WIDX_PATH_CHECK_EDGE_NW MakeWidget(CheckboxGroupOffset(PropertyRowCol({ 12, 0 }, 4, 1), 2, 0), { 12, 12 }, WindowWidgetType::Checkbox, WindowColour::Secondary), // WIDX_PATH_CHECK_EDGE_N - kWidgetsEnd, }; constexpr int32_t NumTrackProperties = 5; constexpr int32_t NumTrackDetails = 7; constexpr int32_t TrackPropertiesHeight = 16 + NumTrackProperties * 21; constexpr int32_t TrackDetailsHeight = 20 + NumTrackDetails * 11; - static Widget TrackWidgets[] = { + static constexpr Widget TrackWidgets[] = { MAIN_TILE_INSPECTOR_WIDGETS, MakeWidget(PropertyRowCol({ 12, 0}, 0, 0), PropertyFullWidth, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_TILE_INSPECTOR_TRACK_ENTIRE_TRACK_PIECE), // WIDX_TRACK_CHECK_APPLY_TO_ALL MakeSpinnerWidgets(PropertyRowCol({ 12, 0 }, 1, 1), PropertyButtonSize, WindowWidgetType::Spinner, WindowColour::Secondary), // WIDX_TRACK_SPINNER_HEIGHT{,_INCREASE,_DECREASE} MakeWidget(PropertyRowCol({ 12, 0}, 2, 0), PropertyFullWidth, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_TILE_INSPECTOR_TRACK_CHAIN_LIFT), // WIDX_TRACK_CHECK_CHAIN_LIFT MakeWidget(PropertyRowCol({ 12, 0}, 3, 0), PropertyFullWidth, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_TILE_INSPECTOR_TRACK_BRAKE_CLOSED), // WIDX_TRACK_CHECK_BRAKE_CLOSED MakeWidget(PropertyRowCol({ 12, 0}, 4, 0), PropertyFullWidth, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_TILE_INSPECTOR_TRACK_IS_INDESTRUCTIBLE), // WIDX_TRACK_CHECK_IS_INDESTRUCTIBLE - kWidgetsEnd, }; constexpr int32_t NumSceneryProperties = 4; // The checkbox groups both count for 2 rows constexpr int32_t NumSceneryDetails = 3; constexpr int32_t SceneryPropertiesHeight = 16 + NumSceneryProperties * 21; constexpr int32_t SceneryDetailsHeight = 20 + NumSceneryDetails * 11; - static Widget SceneryWidgets[] = { + static constexpr Widget SceneryWidgets[] = { MAIN_TILE_INSPECTOR_WIDGETS, MakeSpinnerWidgets(PropertyRowCol({ 12, 0 }, 0, 1), PropertyButtonSize, WindowWidgetType::Spinner, WindowColour::Secondary), // WIDX_SCENERY_SPINNER_HEIGHT{,_INCREASE,_DECREASE} MakeWidget(CheckboxGroupOffset(PropertyRowCol({ 12, 0 }, 1, 1), 1, 0), { 12, 12 }, WindowWidgetType::Checkbox, WindowColour::Secondary), // WIDX_SCENERY_CHECK_QUARTER_N @@ -361,60 +373,54 @@ namespace OpenRCT2::Ui::Windows MakeWidget(CheckboxGroupOffset(PropertyRowCol({ 12, 0 }, 2, 1), 2, 1), { 12, 12 }, WindowWidgetType::Checkbox, WindowColour::Secondary), // WIDX_SCENERY_CHECK_COLLISION_E MakeWidget(CheckboxGroupOffset(PropertyRowCol({ 12, 0 }, 2, 1), 1, 2), { 12, 12 }, WindowWidgetType::Checkbox, WindowColour::Secondary), // WIDX_SCENERY_CHECK_COLLISION_S MakeWidget(CheckboxGroupOffset(PropertyRowCol({ 12, 0 }, 2, 1), 0, 1), { 12, 12 }, WindowWidgetType::Checkbox, WindowColour::Secondary), // WIDX_SCENERY_CHECK_COLLISION_W - kWidgetsEnd, }; constexpr int32_t NumEntranceProperties = 2; constexpr int32_t NumEntranceDetails = 4; constexpr int32_t EntrancePropertiesHeight = 16 + NumEntranceProperties * 21; constexpr int32_t EntranceDetailsHeight = 20 + NumEntranceDetails * 11; - static Widget EntranceWidgets[] = { + static constexpr Widget EntranceWidgets[] = { MAIN_TILE_INSPECTOR_WIDGETS, MakeSpinnerWidgets(PropertyRowCol({ 12, 0 }, 0, 1), PropertyButtonSize, WindowWidgetType::Spinner, WindowColour::Secondary), // WIDX_ENTRANCE_SPINNER_HEIGHT{,_INCREASE,_DECREASE} MakeWidget(PropertyRowCol({ 12, 0 }, 1, 0), PropertyButtonSize, WindowWidgetType::Button, WindowColour::Secondary, STR_TILE_INSPECTOR_ENTRANCE_MAKE_USABLE, STR_TILE_INSPECTOR_ENTRANCE_MAKE_USABLE_TIP), // WIDX_ENTRANCE_BUTTON_MAKE_USABLE - kWidgetsEnd, }; constexpr int32_t NumWallProperties = 4; constexpr int32_t NumWallDetails = 2; constexpr int32_t WallPropertiesHeight = 16 + NumWallProperties * 21; constexpr int32_t WallDetailsHeight = 20 + NumWallDetails * 11; - static Widget WallWidgets[] = { + static constexpr Widget WallWidgets[] = { MAIN_TILE_INSPECTOR_WIDGETS, MakeSpinnerWidgets(PropertyRowCol({ 12, 0 }, 0, 1), PropertyButtonSize, WindowWidgetType::Spinner, WindowColour::Secondary), // WIDX_WALL_SPINNER_HEIGHT{,_INCREASE,_DECREASE} MakeWidget(PropertyRowCol({ 12, 0 }, 1, 1), PropertyButtonSize, WindowWidgetType::DropdownMenu, WindowColour::Secondary), // WIDX_WALL_DROPDOWN_SLOPE MakeWidget(PropertyRowCol({ 12 + PropertyButtonSize.width - 12, 0 }, 1, 1), { 11, 12}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH), // WIDX_WALL_DROPDOWN_SLOPE_BUTTON MakeSpinnerWidgets(PropertyRowCol({ 12, 0 }, 2, 1), PropertyButtonSize, WindowWidgetType::Spinner, WindowColour::Secondary), // WIDX_WALL_SPINNER_ANIMATION_FRAME{,_INCREASE,_DECREASE} MakeWidget(PropertyRowCol({ 12, 0 }, 3, 0), PropertyFullWidth, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_TILE_INSPECTOR_WALL_ANIMATION_IS_BACKWARDS), // WIDX_WALL_ANIMATION_IS_BACKWARDS - kWidgetsEnd, }; constexpr int32_t NumLargeSceneryProperties = 1; constexpr int32_t NumLargeSceneryDetails = 3; constexpr int32_t LargeSceneryPropertiesHeight = 16 + NumLargeSceneryProperties * 21; constexpr int32_t LargeSceneryDetailsHeight = 20 + NumLargeSceneryDetails * 11; - static Widget LargeSceneryWidgets[] = { + static constexpr Widget LargeSceneryWidgets[] = { MAIN_TILE_INSPECTOR_WIDGETS, MakeSpinnerWidgets(PropertyRowCol({ 12, 0 }, 0, 1), PropertyButtonSize, WindowWidgetType::Spinner, WindowColour::Secondary), // WIDX_LARGE_SCENERY_SPINNER_HEIGHT{,_INCREASE,_DECREASE} - kWidgetsEnd, }; constexpr int32_t NumBannerProperties = 3; constexpr int32_t NumBannerDetails = 1; constexpr int32_t BannerPropertiesHeight = 16 + NumBannerProperties * 21; constexpr int32_t BannerDetailsHeight = 20 + NumBannerDetails * 11; - static Widget BannerWidgets[] = { + static constexpr Widget BannerWidgets[] = { MAIN_TILE_INSPECTOR_WIDGETS, MakeSpinnerWidgets(PropertyRowCol({ 12, 0 }, 0, 1), PropertyButtonSize, WindowWidgetType::Spinner, WindowColour::Secondary), // WIDX_BANNER_SPINNER_HEIGHT{,_INCREASE,_DECREASE} MakeWidget(CheckboxGroupOffset(PropertyRowCol({ 12, 0 }, 1, 1), 3, 1), { 12, 12 }, WindowWidgetType::Checkbox, WindowColour::Secondary), // WIDX_BANNER_CHECK_BLOCK_NE MakeWidget(CheckboxGroupOffset(PropertyRowCol({ 12, 0 }, 1, 1), 3, 3), { 12, 12 }, WindowWidgetType::Checkbox, WindowColour::Secondary), // WIDX_BANNER_CHECK_BLOCK_SE MakeWidget(CheckboxGroupOffset(PropertyRowCol({ 12, 0 }, 1, 1), 1, 3), { 12, 12 }, WindowWidgetType::Checkbox, WindowColour::Secondary), // WIDX_BANNER_CHECK_BLOCK_SW MakeWidget(CheckboxGroupOffset(PropertyRowCol({ 12, 0 }, 1, 1), 1, 1), { 12, 12 }, WindowWidgetType::Checkbox, WindowColour::Secondary), // WIDX_BANNER_CHECK_BLOCK_NW - - kWidgetsEnd, }; - static Widget *PageWidgets[] = { + static constexpr std::span PageWidgets[] = { DefaultWidgets, SurfaceWidgets, PathWidgets, @@ -1778,7 +1784,7 @@ static uint64_t PageDisabledWidgets[] = { } tileInspectorPage = p; auto pageIndex = EnumValue(p); - widgets = PageWidgets[pageIndex]; + SetWidgets(PageWidgets[pageIndex]); hold_down_widgets = PageHoldDownWidgets[pageIndex]; disabled_widgets = PageDisabledWidgets[pageIndex]; pressed_widgets = 0; diff --git a/src/openrct2-ui/windows/TitleExit.cpp b/src/openrct2-ui/windows/TitleExit.cpp index 0fd2a4efd7..ef4b3d5837 100644 --- a/src/openrct2-ui/windows/TitleExit.cpp +++ b/src/openrct2-ui/windows/TitleExit.cpp @@ -19,16 +19,15 @@ namespace OpenRCT2::Ui::Windows WIDX_EXIT, }; - static Widget _titleExitWidgets[] = { + static constexpr Widget _titleExitWidgets[] = { MakeWidget({ 0, 0 }, { 40, 64 }, WindowWidgetType::ImgBtn, WindowColour::Tertiary, ImageId(SPR_MENU_EXIT), STR_EXIT), - kWidgetsEnd, }; class TitleExitWindow final : public Window { void OnOpen() override { - widgets = _titleExitWidgets; + SetWidgets(_titleExitWidgets); InitScrollWidgets(); } diff --git a/src/openrct2-ui/windows/TitleLogo.cpp b/src/openrct2-ui/windows/TitleLogo.cpp index fa5b23b83c..81ab20ddf2 100644 --- a/src/openrct2-ui/windows/TitleLogo.cpp +++ b/src/openrct2-ui/windows/TitleLogo.cpp @@ -23,9 +23,8 @@ namespace OpenRCT2::Ui::Windows WIDX_LOGO }; - static Widget _titleLogoWidgets[] = { + static constexpr Widget _titleLogoWidgets[] = { MakeWidget({ 0, 0 }, { WW + 1, WH + 1 }, WindowWidgetType::ImgBtn, WindowColour::Primary), - kWidgetsEnd, }; class TitleLogoWindow final : public Window @@ -37,7 +36,7 @@ namespace OpenRCT2::Ui::Windows */ void OnOpen() override { - widgets = _titleLogoWidgets; + SetWidgets(_titleLogoWidgets); WindowInitScrollWidgets(*this); colours[0] = ColourWithFlags{ COLOUR_GREY }.withFlag(ColourFlag::translucent, true); colours[1] = ColourWithFlags{ COLOUR_GREY }.withFlag(ColourFlag::translucent, true); diff --git a/src/openrct2-ui/windows/TitleMenu.cpp b/src/openrct2-ui/windows/TitleMenu.cpp index 26605532f6..ce3731dc7f 100644 --- a/src/openrct2-ui/windows/TitleMenu.cpp +++ b/src/openrct2-ui/windows/TitleMenu.cpp @@ -47,13 +47,12 @@ namespace OpenRCT2::Ui::Windows static constexpr ScreenSize UpdateButtonDims = { MenuButtonDims.width * 4, 28 }; // clang-format off - static Widget _titleMenuWidgets[] = { + static constexpr Widget _titleMenuWidgets[] = { MakeWidget({0, UpdateButtonDims.height}, MenuButtonDims, WindowWidgetType::ImgBtn, WindowColour::Tertiary, ImageId(SPR_MENU_NEW_GAME), STR_START_NEW_GAME_TIP), MakeWidget({0, UpdateButtonDims.height}, MenuButtonDims, WindowWidgetType::ImgBtn, WindowColour::Tertiary, ImageId(SPR_MENU_LOAD_GAME), STR_CONTINUE_SAVED_GAME_TIP), MakeWidget({0, UpdateButtonDims.height}, MenuButtonDims, WindowWidgetType::ImgBtn, WindowColour::Tertiary, ImageId(SPR_G2_MENU_MULTIPLAYER), STR_SHOW_MULTIPLAYER_TIP), MakeWidget({0, UpdateButtonDims.height}, MenuButtonDims, WindowWidgetType::ImgBtn, WindowColour::Tertiary, ImageId(SPR_MENU_TOOLBOX), STR_GAME_TOOLS_TIP), MakeWidget({0, 0}, UpdateButtonDims, WindowWidgetType::Empty, WindowColour::Secondary, STR_UPDATE_AVAILABLE), - kWidgetsEnd, }; // clang-format on @@ -93,14 +92,14 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = _titleMenuWidgets; + SetWidgets(_titleMenuWidgets); #ifdef DISABLE_NETWORK widgets[WIDX_MULTIPLAYER].type = WindowWidgetType::Empty; #endif int32_t x = 0; - for (Widget* widget = widgets; widget != &widgets[WIDX_NEW_VERSION]; widget++) + for (Widget* widget = widgets.data(); widget != &widgets[WIDX_NEW_VERSION]; widget++) { if (widget->type != WindowWidgetType::Empty) { diff --git a/src/openrct2-ui/windows/TitleOptions.cpp b/src/openrct2-ui/windows/TitleOptions.cpp index 2ab8dcc91d..4657f236e5 100644 --- a/src/openrct2-ui/windows/TitleOptions.cpp +++ b/src/openrct2-ui/windows/TitleOptions.cpp @@ -18,9 +18,8 @@ namespace OpenRCT2::Ui::Windows WIDX_OPTIONS, }; - static Widget _windowTitleOptionsWidgets[] = { + static constexpr Widget _windowTitleOptionsWidgets[] = { MakeWidget({ 0, 0 }, { 80, 15 }, WindowWidgetType::Button, WindowColour::Tertiary, STR_OPTIONS, STR_OPTIONS_TIP), - kWidgetsEnd, }; class TitleOptionsWindow final : public Window @@ -28,7 +27,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = _windowTitleOptionsWidgets; + SetWidgets(_windowTitleOptionsWidgets); WindowInitScrollWidgets(*this); } diff --git a/src/openrct2-ui/windows/TitleVersion.cpp b/src/openrct2-ui/windows/TitleVersion.cpp index 4f1e59e7b0..791a9049fb 100644 --- a/src/openrct2-ui/windows/TitleVersion.cpp +++ b/src/openrct2-ui/windows/TitleVersion.cpp @@ -21,17 +21,8 @@ namespace OpenRCT2::Ui::Windows static constexpr uint8_t kTextOffset = 8; - static Widget _widgets[] = { - kWidgetsEnd, - }; - class TitleVersionWindow final : public Window { - void OnOpen() override - { - widgets = _widgets; - } - void OnDraw(DrawPixelInfo& dpi) override { // Write name and version information diff --git a/src/openrct2-ui/windows/Tooltip.cpp b/src/openrct2-ui/windows/Tooltip.cpp index 89b9e0b527..16454fbc4b 100644 --- a/src/openrct2-ui/windows/Tooltip.cpp +++ b/src/openrct2-ui/windows/Tooltip.cpp @@ -24,9 +24,8 @@ namespace OpenRCT2::Ui::Windows WIDX_BACKGROUND }; - static Widget _tooltipWidgets[] = { + static constexpr Widget _tooltipWidgets[] = { MakeWidget({ 0, 0 }, { 200, 32 }, WindowWidgetType::ImgBtn, WindowColour::Primary), - kWidgetsEnd, }; class TooltipWindow final : public Window @@ -44,7 +43,7 @@ namespace OpenRCT2::Ui::Windows width = textWidth + 5; height = textHeight + 4; - widgets = _tooltipWidgets; + SetWidgets(_tooltipWidgets); widgets[WIDX_BACKGROUND].right = width; widgets[WIDX_BACKGROUND].bottom = height; @@ -165,7 +164,7 @@ namespace OpenRCT2::Ui::Windows void WindowTooltipOpen(WindowBase* widgetWindow, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords) { - if (widgetWindow == nullptr || widgetIndex == -1) + if (widgetWindow == nullptr || widgetIndex == kWidgetIndexNull) return; auto widget = &widgetWindow->widgets[widgetIndex]; diff --git a/src/openrct2-ui/windows/TopToolbar.cpp b/src/openrct2-ui/windows/TopToolbar.cpp index 5c9ae87777..098851dd15 100644 --- a/src/openrct2-ui/windows/TopToolbar.cpp +++ b/src/openrct2-ui/windows/TopToolbar.cpp @@ -236,7 +236,7 @@ namespace OpenRCT2::Ui::Windows #pragma endregion - static Widget _topToolbarWidgets[] = { + static constexpr Widget _topToolbarWidgets[] = { MakeRemapWidget({ 0, 0}, {30, kTopToolbarHeight + 1}, WindowWidgetType::TrnBtn, WindowColour::Primary , SPR_TOOLBAR_PAUSE, STR_PAUSE_GAME_TIP ), // Pause MakeRemapWidget({ 60, 0}, {30, kTopToolbarHeight + 1}, WindowWidgetType::TrnBtn, WindowColour::Primary , SPR_TOOLBAR_FILE, STR_DISC_AND_GAME_OPTIONS_TIP ), // File menu MakeRemapWidget({250, 0}, {30, kTopToolbarHeight + 1}, WindowWidgetType::TrnBtn, WindowColour::Primary , SPR_G2_TOOLBAR_MUTE, STR_TOOLBAR_MUTE_TIP ), // Mute @@ -264,7 +264,6 @@ namespace OpenRCT2::Ui::Windows MakeRemapWidget({ 30, 0}, {30, kTopToolbarHeight + 1}, WindowWidgetType::TrnBtn, WindowColour::Primary , SPR_G2_TOOLBAR_MULTIPLAYER, STR_SHOW_MULTIPLAYER_STATUS_TIP ), // Network MakeRemapWidget({ 30, 0}, {30, kTopToolbarHeight + 1}, WindowWidgetType::TrnBtn, WindowColour::Primary , SPR_TAB_TOOLBAR, STR_TOOLBAR_CHAT_TIP ), // Chat MakeWidget ({ 0, 0}, {10, 1}, WindowWidgetType::Empty, WindowColour::Primary ), // Artificial widget separator - kWidgetsEnd, }; // clang-format on @@ -1003,7 +1002,7 @@ namespace OpenRCT2::Ui::Windows WindowClass::TopToolbar, ScreenCoordsXY(0, 0), ContextGetWidth(), kTopToolbarHeight + 1, WF_STICK_TO_FRONT | WF_TRANSPARENT | WF_NO_BACKGROUND); - window->widgets = _topToolbarWidgets; + window->SetWidgets(_topToolbarWidgets); WindowInitScrollWidgets(*window); diff --git a/src/openrct2-ui/windows/TrackDesignManage.cpp b/src/openrct2-ui/windows/TrackDesignManage.cpp index 1ace39ea5b..c82fbb3c58 100644 --- a/src/openrct2-ui/windows/TrackDesignManage.cpp +++ b/src/openrct2-ui/windows/TrackDesignManage.cpp @@ -40,18 +40,16 @@ namespace OpenRCT2::Ui::Windows }; // clang-format off - static Widget _trackManageWidgets[] = { + static constexpr Widget _trackManageWidgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), MakeWidget({ 10, 24}, {110, 12}, WindowWidgetType::Button, WindowColour::Primary, STR_TRACK_MANAGE_RENAME), MakeWidget({130, 24}, {110, 12}, WindowWidgetType::Button, WindowColour::Primary, STR_TRACK_MANAGE_DELETE), - kWidgetsEnd, }; - static Widget _trackDeletePromptWidgets[] = { + static constexpr Widget _trackDeletePromptWidgets[] = { WINDOW_SHIM(STR_DELETE_FILE, WW_DELETE_PROMPT, WH_DELETE_PROMPT), MakeWidget({ 10, 54}, {110, 12}, WindowWidgetType::Button, WindowColour::Primary, STR_TRACK_MANAGE_DELETE), MakeWidget({130, 54}, {110, 12}, WindowWidgetType::Button, WindowColour::Primary, STR_CANCEL ), - kWidgetsEnd, }; // clang-format on @@ -120,7 +118,7 @@ namespace OpenRCT2::Ui::Windows void TrackDesignManageWindow::OnOpen() { - widgets = _trackManageWidgets; + SetWidgets(_trackManageWidgets); WindowInitScrollWidgets(*this); WindowTrackDesignListSetBeingUpdated(true); @@ -205,7 +203,7 @@ namespace OpenRCT2::Ui::Windows void TrackDeletePromptWindow::OnOpen() { - widgets = _trackDeletePromptWidgets; + SetWidgets(_trackDeletePromptWidgets); WindowInitScrollWidgets(*this); } diff --git a/src/openrct2-ui/windows/TrackDesignPlace.cpp b/src/openrct2-ui/windows/TrackDesignPlace.cpp index 7a6e4cde7f..d35e59895e 100644 --- a/src/openrct2-ui/windows/TrackDesignPlace.cpp +++ b/src/openrct2-ui/windows/TrackDesignPlace.cpp @@ -68,13 +68,12 @@ namespace OpenRCT2::Ui::Windows validate_global_widx(WC_TRACK_DESIGN_PLACE, WIDX_ROTATE); // clang-format off - static Widget _trackPlaceWidgets[] = { + static constexpr Widget _trackPlaceWidgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), MakeWidget({173, 83}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Primary, ImageId(SPR_ROTATE_ARROW), STR_ROTATE_90_TIP ), MakeWidget({173, 59}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Primary, ImageId(SPR_MIRROR_ARROW), STR_MIRROR_IMAGE_TIP ), MakeWidget({ 4, 109}, {192, 12}, WindowWidgetType::Button, WindowColour::Primary, STR_SELECT_A_DIFFERENT_DESIGN, STR_GO_BACK_TO_DESIGN_SELECTION_WINDOW_TIP), MakeWidget({ 0, 0}, { 1, 1}, WindowWidgetType::Empty, WindowColour::Primary), - kWidgetsEnd, }; // clang-format on @@ -103,7 +102,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = _trackPlaceWidgets; + SetWidgets(_trackPlaceWidgets); WindowInitScrollWidgets(*this); ToolSet(*this, WIDX_PRICE, Tool::Crosshair); InputSetFlag(INPUT_FLAG_6, true); diff --git a/src/openrct2-ui/windows/TrackList.cpp b/src/openrct2-ui/windows/TrackList.cpp index 84d6a055c9..bbb102b292 100644 --- a/src/openrct2-ui/windows/TrackList.cpp +++ b/src/openrct2-ui/windows/TrackList.cpp @@ -55,7 +55,7 @@ namespace OpenRCT2::Ui::Windows validate_global_widx(WC_TRACK_DESIGN_LIST, WIDX_ROTATE); // clang-format off - static Widget _trackListWidgets[] = { + static constexpr Widget _trackListWidgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), MakeWidget({ 4, 18}, {218, 13}, WindowWidgetType::TableHeader, WindowColour::Primary, STR_SELECT_OTHER_RIDE ), MakeWidget({ 4, 32}, {124, 13}, WindowWidgetType::TextBox, WindowColour::Secondary ), @@ -64,7 +64,6 @@ namespace OpenRCT2::Ui::Windows MakeWidget({224, 18}, {372, 219}, WindowWidgetType::FlatBtn, WindowColour::Primary ), MakeWidget({572, 405}, { ROTATE_AND_SCENERY_BUTTON_SIZE, ROTATE_AND_SCENERY_BUTTON_SIZE}, WindowWidgetType::FlatBtn, WindowColour::Primary, ImageId(SPR_ROTATE_ARROW), STR_ROTATE_90_TIP ), MakeWidget({572, 381}, { ROTATE_AND_SCENERY_BUTTON_SIZE, ROTATE_AND_SCENERY_BUTTON_SIZE}, WindowWidgetType::FlatBtn, WindowColour::Primary, ImageId(SPR_SCENERY), STR_TOGGLE_SCENERY_TIP ), - kWidgetsEnd, }; // clang-format on @@ -218,8 +217,8 @@ namespace OpenRCT2::Ui::Windows void OnOpen() override { String::set(_filterString, sizeof(_filterString), ""); - _trackListWidgets[WIDX_FILTER_STRING].string = _filterString; - widgets = _trackListWidgets; + SetWidgets(_trackListWidgets); + widgets[WIDX_FILTER_STRING].string = _filterString; LoadDesignsList(_window_track_list_item); diff --git a/src/openrct2-ui/windows/Transparency.cpp b/src/openrct2-ui/windows/Transparency.cpp index 5d658ee9be..77381784cb 100644 --- a/src/openrct2-ui/windows/Transparency.cpp +++ b/src/openrct2-ui/windows/Transparency.cpp @@ -63,7 +63,7 @@ namespace OpenRCT2::Ui::Windows #pragma endregion // clang-format off - static Widget _transparancyWidgets[] = + static constexpr Widget _transparancyWidgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), MakeWidget({ 2, 17}, HIDE_SIZE, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_G2_BUTTON_HIDE_VEGETATION), STR_SEE_THROUGH_VEGETATION), @@ -81,8 +81,6 @@ namespace OpenRCT2::Ui::Windows MakeWidget({ 77, 42}, INVISIBLE_SIZE, WindowWidgetType::FlatBtn, WindowColour::Tertiary, STR_NONE, STR_INVISIBLE_RIDES), MakeWidget({102, 42}, INVISIBLE_SIZE, WindowWidgetType::FlatBtn, WindowColour::Tertiary, STR_NONE, STR_INVISIBLE_VEHICLES), MakeWidget({127, 42}, INVISIBLE_SIZE, WindowWidgetType::FlatBtn, WindowColour::Tertiary, STR_NONE, STR_INVISIBLE_SUPPORTS), - - { kWidgetsEnd }, }; // clang-format on @@ -92,7 +90,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = _transparancyWidgets; + SetWidgets(_transparancyWidgets); WindowPushOthersBelow(*this); auto* w = WindowGetMain(); diff --git a/src/openrct2-ui/windows/ViewClipping.cpp b/src/openrct2-ui/windows/ViewClipping.cpp index 4fc6b75675..15e30a91d1 100644 --- a/src/openrct2-ui/windows/ViewClipping.cpp +++ b/src/openrct2-ui/windows/ViewClipping.cpp @@ -51,7 +51,7 @@ namespace OpenRCT2::Ui::Windows static constexpr int32_t WH = 155; // clang-format off - static Widget _viewClippingWidgets[] = { + static constexpr Widget _viewClippingWidgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), MakeWidget ({ 11, 19}, { 159, 11}, WindowWidgetType::Checkbox, WindowColour::Primary, STR_VIEW_CLIPPING_HEIGHT_ENABLE, STR_VIEW_CLIPPING_HEIGHT_ENABLE_TIP ), // clip enable/disable check box MakeWidget ({ 5, 36}, {WW - 10, 48}, WindowWidgetType::Groupbox, WindowColour::Primary, STR_VIEW_CLIPPING_VERTICAL_CLIPPING ), @@ -60,8 +60,6 @@ namespace OpenRCT2::Ui::Windows MakeWidget ({ 5, 90}, {WW - 10, 60}, WindowWidgetType::Groupbox, WindowColour::Primary, STR_VIEW_CLIPPING_HORIZONTAL_CLIPPING ), MakeWidget ({ 11, 105}, { 158, 17}, WindowWidgetType::Button, WindowColour::Primary, STR_VIEW_CLIPPING_SELECT_AREA ), // selector MakeWidget ({ 11, 126}, { 158, 18}, WindowWidgetType::Button, WindowColour::Primary, STR_VIEW_CLIPPING_CLEAR_SELECTION ), // clear - - kWidgetsEnd, }; // clang-format on @@ -346,7 +344,7 @@ namespace OpenRCT2::Ui::Windows void OnOpen() override { - this->widgets = _viewClippingWidgets; + SetWidgets(_viewClippingWidgets); this->hold_down_widgets = (1uLL << WIDX_CLIP_HEIGHT_INCREASE) | (1uL << WIDX_CLIP_HEIGHT_DECREASE); WindowInitScrollWidgets(*this); diff --git a/src/openrct2-ui/windows/Viewport.cpp b/src/openrct2-ui/windows/Viewport.cpp index e99e01cf95..13476843d1 100644 --- a/src/openrct2-ui/windows/Viewport.cpp +++ b/src/openrct2-ui/windows/Viewport.cpp @@ -43,7 +43,7 @@ namespace OpenRCT2::Ui::Windows #pragma endregion // clang-format off - static Widget _viewportWidgets[] = + static constexpr Widget _viewportWidgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), MakeWidget({ 0, 14}, { WW - 1, WH - 1}, WindowWidgetType::Resize, WindowColour::Secondary ), // resize @@ -52,7 +52,6 @@ namespace OpenRCT2::Ui::Windows MakeWidget({WW - 25, 41}, VIEWPORT_BUTTON, WindowWidgetType::FlatBtn, WindowColour::Primary , ImageId(SPR_G2_ZOOM_OUT), STR_ZOOM_OUT_TIP ), // zoom out MakeWidget({WW - 25, 65}, VIEWPORT_BUTTON, WindowWidgetType::FlatBtn, WindowColour::Primary , ImageId(SPR_LOCATE), STR_LOCATE_SUBJECT_TIP), // locate MakeWidget({WW - 25, 89}, VIEWPORT_BUTTON, WindowWidgetType::FlatBtn, WindowColour::Primary , ImageId(SPR_ROTATE_ARROW),STR_LOCATE_SUBJECT_TIP), // rotate - kWidgetsEnd, }; // clang-format on @@ -76,7 +75,7 @@ namespace OpenRCT2::Ui::Windows { GetFreeViewportNumber(); - widgets = _viewportWidgets; + SetWidgets(_viewportWidgets); // Create viewport ViewportCreate(this, windowPos, width, height, Focus(TileCoordsXYZ(128, 128, 0).ToCoordsXYZ())); diff --git a/src/openrct2-ui/windows/Water.cpp b/src/openrct2-ui/windows/Water.cpp index fecda78373..8427e3ef88 100644 --- a/src/openrct2-ui/windows/Water.cpp +++ b/src/openrct2-ui/windows/Water.cpp @@ -41,12 +41,11 @@ namespace OpenRCT2::Ui::Windows }; // clang-format off - static Widget _waterWidgets[] = { + static constexpr Widget _waterWidgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), MakeWidget ({16, 17}, {44, 32}, WindowWidgetType::ImgBtn, WindowColour::Primary , ImageId(SPR_LAND_TOOL_SIZE_0), STR_NONE), // preview box MakeRemapWidget({17, 18}, {16, 16}, WindowWidgetType::TrnBtn, WindowColour::Tertiary, SPR_LAND_TOOL_DECREASE, STR_ADJUST_SMALLER_WATER_TIP), // decrement size MakeRemapWidget({43, 32}, {16, 16}, WindowWidgetType::TrnBtn, WindowColour::Tertiary, SPR_LAND_TOOL_INCREASE, STR_ADJUST_LARGER_WATER_TIP), // increment size - kWidgetsEnd, }; // clang-format on @@ -59,7 +58,7 @@ namespace OpenRCT2::Ui::Windows public: void OnOpen() override { - widgets = _waterWidgets; + SetWidgets(_waterWidgets); hold_down_widgets = (1uLL << WIDX_INCREMENT) | (1uLL << WIDX_DECREMENT); WindowInitScrollWidgets(*this); WindowPushOthersBelow(*this); diff --git a/src/openrct2-ui/windows/Window.h b/src/openrct2-ui/windows/Window.h index ddc0faaf7d..a953b8954c 100644 --- a/src/openrct2-ui/windows/Window.h +++ b/src/openrct2-ui/windows/Window.h @@ -11,6 +11,7 @@ #include #include +#include #include struct ObjectEntryDescriptor; diff --git a/src/openrct2/Context.h b/src/openrct2/Context.h index 290dce7602..1a8649e6d8 100644 --- a/src/openrct2/Context.h +++ b/src/openrct2/Context.h @@ -25,12 +25,13 @@ enum class CursorID : uint8_t; namespace OpenRCT2 { struct IStream; -} + class Intent; + struct WindowBase; +} // namespace OpenRCT2 + struct ITrackDesignRepository; struct IGameStateSnapshots; -class Intent; -struct WindowBase; struct NewVersionInfo; struct TTFFontDescriptor; @@ -221,12 +222,12 @@ int32_t ContextGetWidth(); int32_t ContextGetHeight(); bool ContextHasFocus(); void ContextSetCursorTrap(bool value); -WindowBase* ContextOpenWindow(WindowClass wc); -WindowBase* ContextOpenDetailWindow(uint8_t type, int32_t id); -WindowBase* ContextOpenWindowView(uint8_t view); -WindowBase* ContextShowError(StringId title, StringId message, const class Formatter& args, bool autoClose = false); -WindowBase* ContextOpenIntent(Intent* intent); -void ContextBroadcastIntent(Intent* intent); +OpenRCT2::WindowBase* ContextOpenWindow(WindowClass wc); +OpenRCT2::WindowBase* ContextOpenDetailWindow(uint8_t type, int32_t id); +OpenRCT2::WindowBase* ContextOpenWindowView(uint8_t view); +OpenRCT2::WindowBase* ContextShowError(StringId title, StringId message, const class Formatter& args, bool autoClose = false); +OpenRCT2::WindowBase* ContextOpenIntent(OpenRCT2::Intent* intent); +void ContextBroadcastIntent(OpenRCT2::Intent* intent); void ContextForceCloseWindowByClass(WindowClass wc); void ContextHandleInput(); void ContextInputHandleKeyboard(bool isTitle); diff --git a/src/openrct2/Game.h b/src/openrct2/Game.h index 9b4908e1b1..e83ddfbd53 100644 --- a/src/openrct2/Game.h +++ b/src/openrct2/Game.h @@ -13,7 +13,11 @@ #include -class Intent; +namespace OpenRCT2 +{ + class Intent; +} + struct ParkLoadResult; enum class GameCommand : int32_t @@ -165,7 +169,7 @@ void PauseToggle(); bool GameIsPaused(); bool GameIsNotPaused(); void SaveGame(); -std::unique_ptr CreateSaveGameAsIntent(); +std::unique_ptr CreateSaveGameAsIntent(); void SaveGameAs(); void SaveGameCmd(u8string_view name = {}); void SaveGameWithName(u8string_view name); diff --git a/src/openrct2/Input.cpp b/src/openrct2/Input.cpp index c25e902ed1..2f85b6a3a2 100644 --- a/src/openrct2/Input.cpp +++ b/src/openrct2/Input.cpp @@ -12,65 +12,68 @@ #include "Context.h" #include "Game.h" -InputState _inputState; -uint8_t _inputFlags; - -WidgetRef gHoverWidget; -WidgetRef gPressedWidget; - -uint32_t _tooltipNotShownTimeout; - -/** - * - * rct2: 0x006E3B43 - */ -void TitleHandleKeyboardInput() +namespace OpenRCT2 { - ContextInputHandleKeyboard(true); -} + InputState _inputState; + uint8_t _inputFlags; -/** - * - * rct2: 0x006E3B43 - */ -void GameHandleKeyboardInput() -{ - ContextInputHandleKeyboard(false); -} + WidgetRef gHoverWidget; + WidgetRef gPressedWidget; -void InputSetFlag(INPUT_FLAGS flag, bool on) -{ - if (on) + uint32_t _tooltipNotShownTimeout; + + /** + * + * rct2: 0x006E3B43 + */ + void TitleHandleKeyboardInput() { - _inputFlags |= flag; + ContextInputHandleKeyboard(true); } - else + + /** + * + * rct2: 0x006E3B43 + */ + void GameHandleKeyboardInput() { - _inputFlags &= ~flag; + ContextInputHandleKeyboard(false); } -} -bool InputTestFlag(INPUT_FLAGS flag) -{ - return _inputFlags & flag; -} + void InputSetFlag(INPUT_FLAGS flag, bool on) + { + if (on) + { + _inputFlags |= flag; + } + else + { + _inputFlags &= ~flag; + } + } -void InputResetFlags() -{ - _inputFlags = 0; -} + bool InputTestFlag(INPUT_FLAGS flag) + { + return _inputFlags & flag; + } -void InputSetState(InputState state) -{ - _inputState = state; -} + void InputResetFlags() + { + _inputFlags = 0; + } -InputState InputGetState() -{ - return _inputState; -} + void InputSetState(InputState state) + { + _inputState = state; + } -void ResetTooltipNotShown() -{ - _tooltipNotShownTimeout = gCurrentRealTimeTicks + 50; -} + InputState InputGetState() + { + return _inputState; + } + + void ResetTooltipNotShown() + { + _tooltipNotShownTimeout = gCurrentRealTimeTicks + 50; + } +} // namespace OpenRCT2 diff --git a/src/openrct2/Input.h b/src/openrct2/Input.h index bf38db927c..8189e18926 100644 --- a/src/openrct2/Input.h +++ b/src/openrct2/Input.h @@ -11,65 +11,68 @@ #include "interface/Window.h" -enum INPUT_FLAGS +namespace OpenRCT2 { - INPUT_FLAG_WIDGET_PRESSED = (1 << 0), + enum INPUT_FLAGS + { + INPUT_FLAG_WIDGET_PRESSED = (1 << 0), - // The dropdown can stay open if the mouse is released, set on flag Dropdown::Flag::StayOpen - INPUT_FLAG_DROPDOWN_STAY_OPEN = (1 << 1), + // The dropdown can stay open if the mouse is released, set on flag Dropdown::Flag::StayOpen + INPUT_FLAG_DROPDOWN_STAY_OPEN = (1 << 1), - // The mouse has been released and the dropdown is still open - // INPUT_FLAG_DROPDOWN_STAY_OPEN is already set if this happens - INPUT_FLAG_DROPDOWN_MOUSE_UP = (1 << 2), + // The mouse has been released and the dropdown is still open + // INPUT_FLAG_DROPDOWN_STAY_OPEN is already set if this happens + INPUT_FLAG_DROPDOWN_MOUSE_UP = (1 << 2), - INPUT_FLAG_TOOL_ACTIVE = (1 << 3), + INPUT_FLAG_TOOL_ACTIVE = (1 << 3), - // Left click on a viewport - INPUT_FLAG_4 = (1 << 4), + // Left click on a viewport + INPUT_FLAG_4 = (1 << 4), - INPUT_FLAG_5 = (1 << 5), + INPUT_FLAG_5 = (1 << 5), - // Some of the map tools (clear, footpath, scenery) - // never read as far as I know. - INPUT_FLAG_6 = (1 << 6), + // Some of the map tools (clear, footpath, scenery) + // never read as far as I know. + INPUT_FLAG_6 = (1 << 6), - INPUT_FLAG_VIEWPORT_SCROLLING = (1 << 7) -}; + INPUT_FLAG_VIEWPORT_SCROLLING = (1 << 7) + }; -enum class InputState -{ - Reset, - Normal, - WidgetPressed, - PositioningWindow, - ViewportRight, - DropdownActive, - ViewportLeft, - ScrollLeft, - Resizing, - ScrollRight -}; + enum class InputState + { + Reset, + Normal, + WidgetPressed, + PositioningWindow, + ViewportRight, + DropdownActive, + ViewportLeft, + ScrollLeft, + Resizing, + ScrollRight + }; -extern WidgetRef gHoverWidget; -extern WidgetRef gPressedWidget; + extern WidgetRef gHoverWidget; + extern WidgetRef gPressedWidget; -extern uint32_t gTooltipCloseTimeout; -extern WidgetRef gTooltipWidget; -extern ScreenCoordsXY gTooltipCursor; + extern uint32_t gTooltipCloseTimeout; + extern WidgetRef gTooltipWidget; + extern ScreenCoordsXY gTooltipCursor; -// TODO: Move to openrct2-ui and make static again -extern InputState _inputState; -extern uint8_t _inputFlags; -extern uint32_t _tooltipNotShownTimeout; + // TODO: Move to openrct2-ui and make static again + extern InputState _inputState; + extern uint8_t _inputFlags; + extern uint32_t _tooltipNotShownTimeout; -void TitleHandleKeyboardInput(); -void GameHandleKeyboardInput(); + void TitleHandleKeyboardInput(); + void GameHandleKeyboardInput(); -void InputSetFlag(INPUT_FLAGS flag, bool on); -bool InputTestFlag(INPUT_FLAGS flag); -void InputResetFlags(); + void InputSetFlag(INPUT_FLAGS flag, bool on); + bool InputTestFlag(INPUT_FLAGS flag); + void InputResetFlags(); -void InputSetState(InputState state); -InputState InputGetState(); + void InputSetState(InputState state); + InputState InputGetState(); -void ResetTooltipNotShown(); + void ResetTooltipNotShown(); +} // namespace OpenRCT2 diff --git a/src/openrct2/actions/RideCreateAction.cpp b/src/openrct2/actions/RideCreateAction.cpp index be4d39e8c6..235106cf61 100644 --- a/src/openrct2/actions/RideCreateAction.cpp +++ b/src/openrct2/actions/RideCreateAction.cpp @@ -28,6 +28,8 @@ #include "../scenario/Scenario.h" #include "../world/Park.h" +#include + using namespace OpenRCT2; RideCreateAction::RideCreateAction( @@ -147,18 +149,12 @@ GameActions::Result RideCreateAction::Execute() const ride->overall_view.SetNull(); ride->SetNameToDefault(); - for (auto& station : ride->GetStations()) - { - station.Start.SetNull(); - station.Entrance.SetNull(); - station.Exit.SetNull(); - station.TrainAtStation = RideStation::kNoTrain; - station.QueueTime = 0; - station.SegmentLength = 0; - station.QueueLength = 0; - station.Length = 0; - station.Height = 0; - } + // Default initialize all stations. + RideStation station{}; + station.Start.SetNull(); + station.Entrance.SetNull(); + station.Exit.SetNull(); + std::ranges::fill(ride->GetStations(), station); ride->status = RideStatus::Closed; ride->NumTrains = 1; diff --git a/src/openrct2/actions/TrackRemoveAction.cpp b/src/openrct2/actions/TrackRemoveAction.cpp index 694b837491..5191487256 100644 --- a/src/openrct2/actions/TrackRemoveAction.cpp +++ b/src/openrct2/actions/TrackRemoveAction.cpp @@ -234,7 +234,7 @@ GameActions::Result TrackRemoveAction::Query() const GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS, STR_ERR_SURFACE_ELEMENT_NOT_FOUND); } - int8_t _support_height = tileElement->BaseHeight - surfaceElement->BaseHeight; + int16_t _support_height = tileElement->BaseHeight - surfaceElement->BaseHeight; if (_support_height < 0) { _support_height = 10; @@ -410,7 +410,7 @@ GameActions::Result TrackRemoveAction::Execute() const GameActions::Status::Unknown, STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS, STR_ERR_SURFACE_ELEMENT_NOT_FOUND); } - int8_t _support_height = tileElement->BaseHeight - surfaceElement->BaseHeight; + int16_t _support_height = tileElement->BaseHeight - surfaceElement->BaseHeight; if (_support_height < 0) { _support_height = 10; diff --git a/src/openrct2/core/OrcaStream.hpp b/src/openrct2/core/OrcaStream.hpp index a4030e4c40..d59cdb53cc 100644 --- a/src/openrct2/core/OrcaStream.hpp +++ b/src/openrct2/core/OrcaStream.hpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -468,15 +469,8 @@ namespace OpenRCT2 } } - template - void ReadWriteArray(TArr (&arr)[TArrSize], TFunc f) - { - auto& arr2 = *(reinterpret_cast*>(arr)); - ReadWriteArray(arr2, f); - } - - template - void ReadWriteArray(std::array& arr, TFunc f) + template + void ReadWriteArray(std::span arr, TFunc f) { if (_mode == Mode::READING) { @@ -487,7 +481,7 @@ namespace OpenRCT2 } for (size_t i = 0; i < count; i++) { - if (i < TArrSize) + if (i < arr.size()) { f(arr[i]); } @@ -509,6 +503,18 @@ namespace OpenRCT2 } } + template + void ReadWriteArray(TArr (&arr)[TArrSize], TFunc f) + { + ReadWriteArray(std::span{ arr, TArrSize }, f); + } + + template + void ReadWriteArray(std::array& arr, TFunc f) + { + ReadWriteArray(std::span{ arr.begin(), arr.end() }, f); + } + template void Ignore() { diff --git a/src/openrct2/entity/EntityRegistry.cpp b/src/openrct2/entity/EntityRegistry.cpp index de7e54a43d..f4592de1d0 100644 --- a/src/openrct2/entity/EntityRegistry.cpp +++ b/src/openrct2/entity/EntityRegistry.cpp @@ -531,6 +531,8 @@ static void FreeEntity(EntityBase& entity) else if (guest != nullptr) { guest->SetName({}); + guest->GuestNextInQueue = EntityId::GetNull(); + OpenRCT2::RideUse::GetHistory().RemoveHandle(guest->Id); OpenRCT2::RideUse::GetTypeHistory().RemoveHandle(guest->Id); } diff --git a/src/openrct2/entity/Guest.cpp b/src/openrct2/entity/Guest.cpp index 9b14e4b5cc..bec70cc448 100644 --- a/src/openrct2/entity/Guest.cpp +++ b/src/openrct2/entity/Guest.cpp @@ -7280,6 +7280,7 @@ Guest* Guest::Generate(const CoordsXYZ& coords) peep->ResetPathfindGoal(); peep->RemoveAllItems(); peep->GuestHeadingToRideId = RideId::GetNull(); + peep->GuestNextInQueue = EntityId::GetNull(); peep->LitterCount = 0; peep->DisgustingCount = 0; peep->VandalismSeen = 0; diff --git a/src/openrct2/interface/InteractiveConsole.cpp b/src/openrct2/interface/InteractiveConsole.cpp index 148cb79e98..b732633506 100644 --- a/src/openrct2/interface/InteractiveConsole.cpp +++ b/src/openrct2/interface/InteractiveConsole.cpp @@ -691,8 +691,8 @@ static void ConsoleCommandGet(InteractiveConsole& console, const arguments_t& ar if (w != nullptr) { Viewport* viewport = WindowGetViewport(w); - auto info = GetMapCoordinatesFromPos( - { viewport->ViewWidth() / 2, viewport->ViewHeight() / 2 }, EnumsToFlags(ViewportInteractionItem::Terrain)); + auto info = GetMapCoordinatesFromPosWindow( + w, { viewport->width / 2, viewport->height / 2 }, EnumsToFlags(ViewportInteractionItem::Terrain)); auto tileMapCoord = TileCoordsXY(info.Loc); console.WriteFormatLine("location %d %d", tileMapCoord.x, tileMapCoord.y); diff --git a/src/openrct2/interface/Viewport.cpp b/src/openrct2/interface/Viewport.cpp index a250b66b40..83acf71165 100644 --- a/src/openrct2/interface/Viewport.cpp +++ b/src/openrct2/interface/Viewport.cpp @@ -50,1974 +50,1980 @@ #include #include -using namespace OpenRCT2; -using namespace OpenRCT2::Numerics; - -enum : uint8_t +namespace OpenRCT2 { - IMAGE_TYPE_DEFAULT = 0, - IMAGE_TYPE_REMAP = (1 << 1), - IMAGE_TYPE_TRANSPARENT = (1 << 2), -}; + using namespace OpenRCT2::Numerics; -uint8_t gShowGridLinesRefCount; -uint8_t gShowLandRightsRefCount; -uint8_t gShowConstructionRightsRefCount; - -static std::list _viewports; -Viewport* g_music_tracking_viewport; - -static std::unique_ptr _paintJobs; -static std::vector _paintColumns; - -InteractionInfo::InteractionInfo(const PaintStruct* ps) - : Loc(ps->MapPos) - , Element(ps->Element) - , Entity(ps->Entity) - , interactionType(ps->InteractionItem) -{ -} - -static void ViewportPaintWeatherGloom(DrawPixelInfo& dpi); -static void ViewportPaint(const Viewport* viewport, DrawPixelInfo& dpi); -static void ViewportUpdateFollowSprite(WindowBase* window); -static void ViewportUpdateSmartFollowEntity(WindowBase* window); -static void ViewportUpdateSmartFollowStaff(WindowBase* window, const Staff& peep); -static void ViewportUpdateSmartFollowVehicle(WindowBase* window); -static void ViewportInvalidate(const Viewport* viewport, const ScreenRect& screenRect); - -/** - * This is not a viewport function. It is used to setup many variables for - * multiple things. - * rct2: 0x006E6EAC - */ -void ViewportInitAll() -{ - if (!gOpenRCT2NoGraphics) + enum : uint8_t + { + IMAGE_TYPE_DEFAULT = 0, + IMAGE_TYPE_REMAP = (1 << 1), + IMAGE_TYPE_TRANSPARENT = (1 << 2), + }; + + uint8_t gShowGridLinesRefCount; + uint8_t gShowLandRightsRefCount; + uint8_t gShowConstructionRightsRefCount; + + static std::list _viewports; + Viewport* g_music_tracking_viewport; + + static std::unique_ptr _paintJobs; + static std::vector _paintColumns; + + InteractionInfo::InteractionInfo(const PaintStruct* ps) + : Loc(ps->MapPos) + , Element(ps->Element) + , Entity(ps->Entity) + , interactionType(ps->InteractionItem) { - ColoursInitMaps(); } - WindowInitAll(); + static void ViewportPaintWeatherGloom(DrawPixelInfo& dpi); + static void ViewportPaint(const Viewport* viewport, DrawPixelInfo& dpi); + static void ViewportUpdateFollowSprite(WindowBase* window); + static void ViewportUpdateSmartFollowEntity(WindowBase* window); + static void ViewportUpdateSmartFollowStaff(WindowBase* window, const Staff& peep); + static void ViewportUpdateSmartFollowVehicle(WindowBase* window); + static void ViewportInvalidate(const Viewport* viewport, const ScreenRect& screenRect); - // ? - InputResetFlags(); - InputSetState(InputState::Reset); - gPressedWidget.window_classification = WindowClass::Null; - gPickupPeepImage = ImageId(); - ResetTooltipNotShown(); - gMapSelectFlags = 0; - ClearPatrolAreaToRender(); - TextinputCancel(); -} - -/** - * Converts between 3d point of a sprite to 2d coordinates for centring on that - * sprite - * rct2: 0x006EB0C1 - * x : ax - * y : bx - * z : cx - * out_x : ax - * out_y : bx - */ -std::optional centre_2d_coordinates(const CoordsXYZ& loc, Viewport* viewport) -{ - // If the start location was invalid - // propagate the invalid location to the output. - // This fixes a bug that caused the game to enter an infinite loop. - if (loc.IsNull()) + /** + * This is not a viewport function. It is used to setup many variables for + * multiple things. + * rct2: 0x006E6EAC + */ + void ViewportInitAll() { - return std::nullopt; + if (!gOpenRCT2NoGraphics) + { + ColoursInitMaps(); + } + + WindowInitAll(); + + // ? + InputResetFlags(); + InputSetState(InputState::Reset); + gPressedWidget.window_classification = WindowClass::Null; + gPickupPeepImage = ImageId(); + ResetTooltipNotShown(); + gMapSelectFlags = 0; + ClearPatrolAreaToRender(); + TextinputCancel(); } - auto screenCoord = Translate3DTo2DWithZ(viewport->rotation, loc); - screenCoord.x -= viewport->ViewWidth() / 2; - screenCoord.y -= viewport->ViewHeight() / 2; - return { screenCoord }; -} + /** + * Converts between 3d point of a sprite to 2d coordinates for centring on that + * sprite + * rct2: 0x006EB0C1 + * x : ax + * y : bx + * z : cx + * out_x : ax + * out_y : bx + */ + std::optional centre_2d_coordinates(const CoordsXYZ& loc, Viewport* viewport) + { + // If the start location was invalid + // propagate the invalid location to the output. + // This fixes a bug that caused the game to enter an infinite loop. + if (loc.IsNull()) + { + return std::nullopt; + } -CoordsXYZ Focus::GetPos() const -{ - return std::visit( - [](auto&& arg) { - using T = std::decay_t; - if constexpr (std::is_same_v) - return arg; - else if constexpr (std::is_same_v) - { - auto* centreEntity = GetEntity(arg); - if (centreEntity != nullptr) + auto screenCoord = Translate3DTo2DWithZ(viewport->rotation, loc); + screenCoord.x -= viewport->ViewWidth() / 2; + screenCoord.y -= viewport->ViewHeight() / 2; + return { screenCoord }; + } + + CoordsXYZ Focus::GetPos() const + { + return std::visit( + [](auto&& arg) { + using T = std::decay_t; + if constexpr (std::is_same_v) + return arg; + else if constexpr (std::is_same_v) { - return CoordsXYZ{ centreEntity->x, centreEntity->y, centreEntity->z }; + auto* centreEntity = GetEntity(arg); + if (centreEntity != nullptr) + { + return CoordsXYZ{ centreEntity->x, centreEntity->y, centreEntity->z }; + } + else + { + LOG_ERROR("Invalid entity for focus."); + return CoordsXYZ{}; + } } - else - { - LOG_ERROR("Invalid entity for focus."); - return CoordsXYZ{}; - } - } - }, - data); -} - -/** - * Viewport will look at sprite or at coordinates as specified in flags 0b_1X - * for sprite 0b_0X for coordinates - * - * rct2: 0x006EB009 - * x: ax - * y: eax (top 16) - * width: bx - * height: ebx (top 16) - * zoom: cl (8 bits) - * centre_x: edx lower 16 bits - * centre_y: edx upper 16 bits - * centre_z: ecx upper 16 bits - * sprite: edx lower 16 bits - * flags: edx top most 2 bits 0b_X1 for zoom clear see below for 2nd bit. - * w: esi - */ -void ViewportCreate(WindowBase* w, const ScreenCoordsXY& screenCoords, int32_t width, int32_t height, const Focus& focus) -{ - Viewport* viewport = nullptr; - if (_viewports.size() >= kMaxViewportCount) - { - LOG_ERROR("No more viewport slots left to allocate."); - return; + }, + data); } - auto itViewport = _viewports.insert(_viewports.end(), Viewport{}); - - viewport = &*itViewport; - viewport->pos = screenCoords; - viewport->width = width; - viewport->height = height; - - const auto zoom = focus.zoom; - viewport->zoom = zoom; - viewport->flags = 0; - viewport->rotation = GetCurrentRotation(); - - if (Config::Get().general.AlwaysShowGridlines) - viewport->flags |= VIEWPORT_FLAG_GRIDLINES; - w->viewport = viewport; - - CoordsXYZ centrePos = focus.GetPos(); - w->viewport_target_sprite = std::visit( - [](auto&& arg) { - using T = std::decay_t; - if constexpr (std::is_same_v) - return EntityId::GetNull(); - else if constexpr (std::is_same_v) - return arg; - }, - focus.data); - - auto centreLoc = centre_2d_coordinates(centrePos, viewport); - if (!centreLoc.has_value()) + /** + * Viewport will look at sprite or at coordinates as specified in flags 0b_1X + * for sprite 0b_0X for coordinates + * + * rct2: 0x006EB009 + * x: ax + * y: eax (top 16) + * width: bx + * height: ebx (top 16) + * zoom: cl (8 bits) + * centre_x: edx lower 16 bits + * centre_y: edx upper 16 bits + * centre_z: ecx upper 16 bits + * sprite: edx lower 16 bits + * flags: edx top most 2 bits 0b_X1 for zoom clear see below for 2nd bit. + * w: esi + */ + void ViewportCreate(WindowBase* w, const ScreenCoordsXY& screenCoords, int32_t width, int32_t height, const Focus& focus) { - LOG_ERROR("Invalid location for viewport."); - return; - } - w->savedViewPos = *centreLoc; - viewport->viewPos = *centreLoc; -} - -void ViewportRemove(Viewport* viewport) -{ - auto it = std::find_if(_viewports.begin(), _viewports.end(), [viewport](const auto& vp) { return &vp == viewport; }); - if (it == _viewports.end()) - { - LOG_ERROR("Unable to remove viewport: %p", viewport); - return; - } - _viewports.erase(it); -} - -static Viewport* ViewportGetMain() -{ - auto mainWindow = WindowGetMain(); - if (mainWindow == nullptr) - { - return nullptr; - } - return mainWindow->viewport; -} - -void ViewportsInvalidate(int32_t x, int32_t y, int32_t z0, int32_t z1, ZoomLevel maxZoom) -{ - for (auto& vp : _viewports) - { - if (maxZoom == ZoomLevel{ -1 } || vp.zoom <= ZoomLevel{ maxZoom }) + Viewport* viewport = nullptr; + if (_viewports.size() >= kMaxViewportCount) { - int32_t x1, y1, x2, y2; - - x += 16; - y += 16; - auto screenCoord = Translate3DTo2DWithZ(vp.rotation, CoordsXYZ{ x, y, 0 }); - - x1 = screenCoord.x - 32; - y1 = screenCoord.y - 32 - z1; - x2 = screenCoord.x + 32; - y2 = screenCoord.y + 32 - z0; - - ViewportInvalidate(&vp, ScreenRect{ { x1, y1 }, { x2, y2 } }); - } - } -} - -void ViewportsInvalidate(const CoordsXYZ& pos, int32_t width, int32_t minHeight, int32_t maxHeight, ZoomLevel maxZoom) -{ - for (auto& vp : _viewports) - { - if (maxZoom == ZoomLevel{ -1 } || vp.zoom <= ZoomLevel{ maxZoom }) - { - auto screenCoords = Translate3DTo2DWithZ(vp.rotation, pos); - auto screenPos = ScreenRect( - screenCoords - ScreenCoordsXY{ width, minHeight }, screenCoords + ScreenCoordsXY{ width, maxHeight }); - - ViewportInvalidate(&vp, screenPos); - } - } -} - -void ViewportsInvalidate(const ScreenRect& screenRect, ZoomLevel maxZoom) -{ - for (auto& vp : _viewports) - { - if (maxZoom == ZoomLevel{ -1 } || vp.zoom <= ZoomLevel{ maxZoom }) - { - ViewportInvalidate(&vp, screenRect); - } - } -} - -/** - * - * rct2: 0x00689174 - * edx is assumed to be (and always is) the current rotation, so it is not - * needed as parameter. - */ -CoordsXYZ ViewportAdjustForMapHeight(const ScreenCoordsXY& startCoords, uint8_t rotation) -{ - int32_t height = 0; - - CoordsXY pos{}; - for (int32_t i = 0; i < 6; i++) - { - pos = ViewportPosToMapPos(startCoords, height, rotation); - height = TileElementHeight(pos); - - // HACK: This is to prevent the x and y values being set to values outside - // of the map. This can happen when the height is larger than the map size. - auto mapSizeMinus2 = GetMapSizeMinus2(); - if (pos.x > mapSizeMinus2.x && pos.y > mapSizeMinus2.y) - { - static constexpr CoordsXY corr[] = { - { -1, -1 }, - { 1, -1 }, - { 1, 1 }, - { -1, 1 }, - }; - pos.x += corr[rotation].x * height; - pos.y += corr[rotation].y * height; - } - } - - return { pos, height }; -} - -/* - * rct2: 0x006E7FF3 - */ -static void ViewportRedrawAfterShift( - DrawPixelInfo& dpi, WindowBase* window, const WindowBase* originalWindow, const ScreenCoordsXY shift, - const ScreenRect& drawRect) -{ - // sub-divide by intersecting windows - if (window != nullptr) - { - // skip current window and non-intersecting windows - if (window == originalWindow || drawRect.GetRight() <= window->windowPos.x - || drawRect.GetLeft() >= window->windowPos.x + window->width || drawRect.GetBottom() <= window->windowPos.y - || drawRect.GetTop() >= window->windowPos.y + window->height) - { - auto itWindowPos = WindowGetIterator(window); - auto itNextWindow = itWindowPos != g_window_list.end() ? std::next(itWindowPos) : g_window_list.end(); - ViewportRedrawAfterShift( - dpi, itNextWindow == g_window_list.end() ? nullptr : itNextWindow->get(), originalWindow, shift, drawRect); + LOG_ERROR("No more viewport slots left to allocate."); return; } - if (drawRect.GetLeft() < window->windowPos.x) - { - ScreenRect leftRect = { drawRect.Point1, { window->windowPos.x, drawRect.GetBottom() } }; - ViewportRedrawAfterShift(dpi, window, originalWindow, shift, leftRect); + auto itViewport = _viewports.insert(_viewports.end(), Viewport{}); - ScreenRect rightRect = { { window->windowPos.x, drawRect.GetTop() }, drawRect.Point2 }; - ViewportRedrawAfterShift(dpi, window, originalWindow, shift, rightRect); + viewport = &*itViewport; + viewport->pos = screenCoords; + viewport->width = width; + viewport->height = height; + + const auto zoom = focus.zoom; + viewport->zoom = zoom; + viewport->flags = 0; + viewport->rotation = GetCurrentRotation(); + + if (Config::Get().general.AlwaysShowGridlines) + viewport->flags |= VIEWPORT_FLAG_GRIDLINES; + w->viewport = viewport; + + CoordsXYZ centrePos = focus.GetPos(); + w->viewport_target_sprite = std::visit( + [](auto&& arg) { + using T = std::decay_t; + if constexpr (std::is_same_v) + return EntityId::GetNull(); + else if constexpr (std::is_same_v) + return arg; + }, + focus.data); + + auto centreLoc = centre_2d_coordinates(centrePos, viewport); + if (!centreLoc.has_value()) + { + LOG_ERROR("Invalid location for viewport."); + return; } - else if (drawRect.GetRight() > window->windowPos.x + window->width) - { - ScreenRect leftRect = { drawRect.Point1, { window->windowPos.x + window->width, drawRect.GetBottom() } }; - ViewportRedrawAfterShift(dpi, window, originalWindow, shift, leftRect); + w->savedViewPos = *centreLoc; + viewport->viewPos = *centreLoc; + } - ScreenRect rightRect = { { window->windowPos.x + window->width, drawRect.GetTop() }, drawRect.Point2 }; - ViewportRedrawAfterShift(dpi, window, originalWindow, shift, rightRect); + void ViewportRemove(Viewport* viewport) + { + auto it = std::find_if(_viewports.begin(), _viewports.end(), [viewport](const auto& vp) { return &vp == viewport; }); + if (it == _viewports.end()) + { + LOG_ERROR("Unable to remove viewport: %p", viewport); + return; } - else if (drawRect.GetTop() < window->windowPos.y) - { - ScreenRect topRect = { drawRect.Point1, { drawRect.GetRight(), window->windowPos.y } }; - ViewportRedrawAfterShift(dpi, window, originalWindow, shift, topRect); + _viewports.erase(it); + } - ScreenRect bottomRect = { { drawRect.GetLeft(), window->windowPos.y }, drawRect.Point2 }; - ViewportRedrawAfterShift(dpi, window, originalWindow, shift, bottomRect); + static Viewport* ViewportGetMain() + { + auto mainWindow = WindowGetMain(); + if (mainWindow == nullptr) + { + return nullptr; } - else if (drawRect.GetBottom() > window->windowPos.y + window->height) - { - ScreenRect topRect = { drawRect.Point1, { drawRect.GetRight(), window->windowPos.y + window->height } }; - ViewportRedrawAfterShift(dpi, window, originalWindow, shift, topRect); + return mainWindow->viewport; + } - ScreenRect bottomRect = { { drawRect.GetLeft(), window->windowPos.y + window->height }, drawRect.Point2 }; - ViewportRedrawAfterShift(dpi, window, originalWindow, shift, bottomRect); + void ViewportsInvalidate(int32_t x, int32_t y, int32_t z0, int32_t z1, ZoomLevel maxZoom) + { + for (auto& vp : _viewports) + { + if (maxZoom == ZoomLevel{ -1 } || vp.zoom <= ZoomLevel{ maxZoom }) + { + int32_t x1, y1, x2, y2; + + x += 16; + y += 16; + auto screenCoord = Translate3DTo2DWithZ(vp.rotation, CoordsXYZ{ x, y, 0 }); + + x1 = screenCoord.x - 32; + y1 = screenCoord.y - 32 - z1; + x2 = screenCoord.x + 32; + y2 = screenCoord.y + 32 - z0; + + ViewportInvalidate(&vp, ScreenRect{ { x1, y1 }, { x2, y2 } }); + } } } - else + + void ViewportsInvalidate(const CoordsXYZ& pos, int32_t width, int32_t minHeight, int32_t maxHeight, ZoomLevel maxZoom) { - auto left = drawRect.GetLeft(); - auto right = drawRect.GetRight(); - auto top = drawRect.GetTop(); - auto bottom = drawRect.GetBottom(); - - // if moved more than the draw rectangle size - if (abs(shift.x) < drawRect.GetWidth() && abs(shift.y) < drawRect.GetHeight()) + for (auto& vp : _viewports) { - // update whole block ? - DrawingEngineCopyRect( - drawRect.GetLeft(), drawRect.GetTop(), drawRect.GetWidth(), drawRect.GetHeight(), shift.x, shift.y); + if (maxZoom == ZoomLevel{ -1 } || vp.zoom <= ZoomLevel{ maxZoom }) + { + auto screenCoords = Translate3DTo2DWithZ(vp.rotation, pos); + auto screenPos = ScreenRect( + screenCoords - ScreenCoordsXY{ width, minHeight }, screenCoords + ScreenCoordsXY{ width, maxHeight }); - if (shift.x > 0) - { - // draw left - auto _right = left + shift.x; - WindowDrawAll(dpi, left, top, _right, bottom); - left += shift.x; + ViewportInvalidate(&vp, screenPos); } - else if (shift.x < 0) + } + } + + void ViewportsInvalidate(const ScreenRect& screenRect, ZoomLevel maxZoom) + { + for (auto& vp : _viewports) + { + if (maxZoom == ZoomLevel{ -1 } || vp.zoom <= ZoomLevel{ maxZoom }) { - // draw right - auto _left = right + shift.x; - WindowDrawAll(dpi, _left, top, right, bottom); - right += shift.x; + ViewportInvalidate(&vp, screenRect); + } + } + } + + /** + * + * rct2: 0x00689174 + * edx is assumed to be (and always is) the current rotation, so it is not + * needed as parameter. + */ + CoordsXYZ ViewportAdjustForMapHeight(const ScreenCoordsXY& startCoords, uint8_t rotation) + { + int32_t height = 0; + + CoordsXY pos{}; + for (int32_t i = 0; i < 6; i++) + { + pos = ViewportPosToMapPos(startCoords, height, rotation); + height = TileElementHeight(pos); + + // HACK: This is to prevent the x and y values being set to values outside + // of the map. This can happen when the height is larger than the map size. + auto mapSizeMinus2 = GetMapSizeMinus2(); + if (pos.x > mapSizeMinus2.x && pos.y > mapSizeMinus2.y) + { + static constexpr CoordsXY corr[] = { + { -1, -1 }, + { 1, -1 }, + { 1, 1 }, + { -1, 1 }, + }; + pos.x += corr[rotation].x * height; + pos.y += corr[rotation].y * height; + } + } + + return { pos, height }; + } + + /* + * rct2: 0x006E7FF3 + */ + static void ViewportRedrawAfterShift( + DrawPixelInfo& dpi, WindowBase* window, const WindowBase* originalWindow, const ScreenCoordsXY shift, + const ScreenRect& drawRect) + { + // sub-divide by intersecting windows + if (window != nullptr) + { + // skip current window and non-intersecting windows + if (window == originalWindow || drawRect.GetRight() <= window->windowPos.x + || drawRect.GetLeft() >= window->windowPos.x + window->width || drawRect.GetBottom() <= window->windowPos.y + || drawRect.GetTop() >= window->windowPos.y + window->height) + { + auto itWindowPos = WindowGetIterator(window); + auto itNextWindow = itWindowPos != g_window_list.end() ? std::next(itWindowPos) : g_window_list.end(); + ViewportRedrawAfterShift( + dpi, itNextWindow == g_window_list.end() ? nullptr : itNextWindow->get(), originalWindow, shift, drawRect); + return; } - if (shift.y > 0) + if (drawRect.GetLeft() < window->windowPos.x) { - // draw top - bottom = top + shift.y; - WindowDrawAll(dpi, left, top, right, bottom); + ScreenRect leftRect = { drawRect.Point1, { window->windowPos.x, drawRect.GetBottom() } }; + ViewportRedrawAfterShift(dpi, window, originalWindow, shift, leftRect); + + ScreenRect rightRect = { { window->windowPos.x, drawRect.GetTop() }, drawRect.Point2 }; + ViewportRedrawAfterShift(dpi, window, originalWindow, shift, rightRect); } - else if (shift.y < 0) + else if (drawRect.GetRight() > window->windowPos.x + window->width) { - // draw bottom - top = bottom + shift.y; - WindowDrawAll(dpi, left, top, right, bottom); + ScreenRect leftRect = { drawRect.Point1, { window->windowPos.x + window->width, drawRect.GetBottom() } }; + ViewportRedrawAfterShift(dpi, window, originalWindow, shift, leftRect); + + ScreenRect rightRect = { { window->windowPos.x + window->width, drawRect.GetTop() }, drawRect.Point2 }; + ViewportRedrawAfterShift(dpi, window, originalWindow, shift, rightRect); + } + else if (drawRect.GetTop() < window->windowPos.y) + { + ScreenRect topRect = { drawRect.Point1, { drawRect.GetRight(), window->windowPos.y } }; + ViewportRedrawAfterShift(dpi, window, originalWindow, shift, topRect); + + ScreenRect bottomRect = { { drawRect.GetLeft(), window->windowPos.y }, drawRect.Point2 }; + ViewportRedrawAfterShift(dpi, window, originalWindow, shift, bottomRect); + } + else if (drawRect.GetBottom() > window->windowPos.y + window->height) + { + ScreenRect topRect = { drawRect.Point1, { drawRect.GetRight(), window->windowPos.y + window->height } }; + ViewportRedrawAfterShift(dpi, window, originalWindow, shift, topRect); + + ScreenRect bottomRect = { { drawRect.GetLeft(), window->windowPos.y + window->height }, drawRect.Point2 }; + ViewportRedrawAfterShift(dpi, window, originalWindow, shift, bottomRect); } } else { - // redraw whole draw rectangle - WindowDrawAll(dpi, left, top, right, bottom); + auto left = drawRect.GetLeft(); + auto right = drawRect.GetRight(); + auto top = drawRect.GetTop(); + auto bottom = drawRect.GetBottom(); + + // if moved more than the draw rectangle size + if (abs(shift.x) < drawRect.GetWidth() && abs(shift.y) < drawRect.GetHeight()) + { + // update whole block ? + DrawingEngineCopyRect( + drawRect.GetLeft(), drawRect.GetTop(), drawRect.GetWidth(), drawRect.GetHeight(), shift.x, shift.y); + + if (shift.x > 0) + { + // draw left + auto _right = left + shift.x; + WindowDrawAll(dpi, left, top, _right, bottom); + left += shift.x; + } + else if (shift.x < 0) + { + // draw right + auto _left = right + shift.x; + WindowDrawAll(dpi, _left, top, right, bottom); + right += shift.x; + } + + if (shift.y > 0) + { + // draw top + bottom = top + shift.y; + WindowDrawAll(dpi, left, top, right, bottom); + } + else if (shift.y < 0) + { + // draw bottom + top = bottom + shift.y; + WindowDrawAll(dpi, left, top, right, bottom); + } + } + else + { + // redraw whole draw rectangle + WindowDrawAll(dpi, left, top, right, bottom); + } } } -} -static void ViewportShiftPixels(DrawPixelInfo& dpi, WindowBase* window, Viewport* viewport, int32_t x_diff, int32_t y_diff) -{ - // This loop redraws all parts covered by transparent windows. - auto it = WindowGetIterator(window); - for (; it != g_window_list.end(); it++) + static void ViewportShiftPixels(DrawPixelInfo& dpi, WindowBase* window, Viewport* viewport, int32_t x_diff, int32_t y_diff) { - auto w = it->get(); - if (!(w->flags & WF_TRANSPARENT)) - continue; - if (w->viewport == viewport) - continue; + // This loop redraws all parts covered by transparent windows. + auto it = WindowGetIterator(window); + for (; it != g_window_list.end(); it++) + { + auto w = it->get(); + if (!(w->flags & WF_TRANSPARENT)) + continue; + if (w->viewport == viewport) + continue; - if (viewport->pos.x + viewport->width <= w->windowPos.x) - continue; - if (w->windowPos.x + w->width <= viewport->pos.x) - continue; + if (viewport->pos.x + viewport->width <= w->windowPos.x) + continue; + if (w->windowPos.x + w->width <= viewport->pos.x) + continue; - if (viewport->pos.y + viewport->height <= w->windowPos.y) - continue; - if (w->windowPos.y + w->height <= viewport->pos.y) - continue; + if (viewport->pos.y + viewport->height <= w->windowPos.y) + continue; + if (w->windowPos.y + w->height <= viewport->pos.y) + continue; - auto left = w->windowPos.x; - auto right = w->windowPos.x + w->width; - auto top = w->windowPos.y; - auto bottom = w->windowPos.y + w->height; + auto left = w->windowPos.x; + auto right = w->windowPos.x + w->width; + auto top = w->windowPos.y; + auto bottom = w->windowPos.y + w->height; - if (left < viewport->pos.x) - left = viewport->pos.x; - if (right > viewport->pos.x + viewport->width) - right = viewport->pos.x + viewport->width; + if (left < viewport->pos.x) + left = viewport->pos.x; + if (right > viewport->pos.x + viewport->width) + right = viewport->pos.x + viewport->width; - if (top < viewport->pos.y) - top = viewport->pos.y; - if (bottom > viewport->pos.y + viewport->height) - bottom = viewport->pos.y + viewport->height; + if (top < viewport->pos.y) + top = viewport->pos.y; + if (bottom > viewport->pos.y + viewport->height) + bottom = viewport->pos.y + viewport->height; - if (left >= right) - continue; - if (top >= bottom) - continue; + if (left >= right) + continue; + if (top >= bottom) + continue; - WindowDrawAll(dpi, left, top, right, bottom); + WindowDrawAll(dpi, left, top, right, bottom); + } + + ViewportRedrawAfterShift( + dpi, window, window, { x_diff, y_diff }, + { viewport->pos, { viewport->pos.x + viewport->width, viewport->pos.y + viewport->height } }); } - ViewportRedrawAfterShift( - dpi, window, window, { x_diff, y_diff }, - { viewport->pos, { viewport->pos.x + viewport->width, viewport->pos.y + viewport->height } }); -} - -static void ViewportMove(const ScreenCoordsXY& coords, WindowBase* w, Viewport* viewport) -{ - auto zoom = viewport->zoom; - - // Note: do not do the subtraction and then divide! - // Note: Due to arithmetic shift != /zoom a shift will have to be used - // hopefully when 0x006E7FF3 is finished this can be converted to /zoom. - auto x_diff = viewport->zoom.ApplyInversedTo(viewport->viewPos.x) - viewport->zoom.ApplyInversedTo(coords.x); - auto y_diff = viewport->zoom.ApplyInversedTo(viewport->viewPos.y) - viewport->zoom.ApplyInversedTo(coords.y); - - viewport->viewPos = coords; - - // If no change in viewing area - if ((!x_diff) && (!y_diff)) - return; - - if (w->flags & WF_7) + static void ViewportMove(const ScreenCoordsXY& coords, WindowBase* w, Viewport* viewport) { - int32_t left = std::max(viewport->pos.x, 0); - int32_t top = std::max(viewport->pos.y, 0); - int32_t right = std::min(viewport->pos.x + viewport->width, ContextGetWidth()); - int32_t bottom = std::min(viewport->pos.y + viewport->height, ContextGetHeight()); + auto zoom = viewport->zoom; - if (left >= right) + // Note: do not do the subtraction and then divide! + // Note: Due to arithmetic shift != /zoom a shift will have to be used + // hopefully when 0x006E7FF3 is finished this can be converted to /zoom. + auto x_diff = viewport->zoom.ApplyInversedTo(viewport->viewPos.x) - viewport->zoom.ApplyInversedTo(coords.x); + auto y_diff = viewport->zoom.ApplyInversedTo(viewport->viewPos.y) - viewport->zoom.ApplyInversedTo(coords.y); + + viewport->viewPos = coords; + + // If no change in viewing area + if ((!x_diff) && (!y_diff)) return; - if (top >= bottom) + + if (w->flags & WF_7) + { + int32_t left = std::max(viewport->pos.x, 0); + int32_t top = std::max(viewport->pos.y, 0); + int32_t right = std::min(viewport->pos.x + viewport->width, ContextGetWidth()); + int32_t bottom = std::min(viewport->pos.y + viewport->height, ContextGetHeight()); + + if (left >= right) + return; + if (top >= bottom) + return; + + if (DrawingEngineHasDirtyOptimisations()) + { + DrawPixelInfo& dpi = DrawingEngineGetDpi(); + WindowDrawAll(dpi, left, top, right, bottom); + return; + } + } + + Viewport view_copy = *viewport; + + if (viewport->pos.x < 0) + { + viewport->width += viewport->pos.x; + viewport->viewPos.x -= zoom.ApplyTo(viewport->pos.x); + viewport->pos.x = 0; + } + + int32_t eax = viewport->pos.x + viewport->width - ContextGetWidth(); + if (eax > 0) + { + viewport->width -= eax; + } + + if (viewport->width <= 0) + { + *viewport = view_copy; return; + } + + if (viewport->pos.y < 0) + { + viewport->height += viewport->pos.y; + viewport->viewPos.y -= zoom.ApplyTo(viewport->pos.y); + viewport->pos.y = 0; + } + + eax = viewport->pos.y + viewport->height - ContextGetHeight(); + if (eax > 0) + { + viewport->height -= eax; + } + + if (viewport->height <= 0) + { + *viewport = view_copy; + return; + } if (DrawingEngineHasDirtyOptimisations()) { DrawPixelInfo& dpi = DrawingEngineGetDpi(); - WindowDrawAll(dpi, left, top, right, bottom); + ViewportShiftPixels(dpi, w, viewport, x_diff, y_diff); + } + + *viewport = view_copy; + } + + // rct2: 0x006E7A15 + static void ViewportSetUndergroundFlag(int32_t underground, WindowBase* window, Viewport* viewport) + { + if (window->classification != WindowClass::MainWindow + || (window->classification == WindowClass::MainWindow && !window->viewport_smart_follow_sprite.IsNull())) + { + if (!underground) + { + int32_t bit = viewport->flags & VIEWPORT_FLAG_UNDERGROUND_INSIDE; + viewport->flags &= ~VIEWPORT_FLAG_UNDERGROUND_INSIDE; + if (!bit) + return; + } + else + { + int32_t bit = viewport->flags & VIEWPORT_FLAG_UNDERGROUND_INSIDE; + viewport->flags |= VIEWPORT_FLAG_UNDERGROUND_INSIDE; + if (bit) + return; + } + window->Invalidate(); + } + } + + /** + * + * rct2: 0x006E7A3A + */ + void ViewportUpdatePosition(WindowBase* window) + { + window->OnResize(); + + Viewport* viewport = window->viewport; + if (viewport == nullptr) return; - } - } - Viewport view_copy = *viewport; - - if (viewport->pos.x < 0) - { - viewport->width += viewport->pos.x; - viewport->viewPos.x -= zoom.ApplyTo(viewport->pos.x); - viewport->pos.x = 0; - } - - int32_t eax = viewport->pos.x + viewport->width - ContextGetWidth(); - if (eax > 0) - { - viewport->width -= eax; - } - - if (viewport->width <= 0) - { - *viewport = view_copy; - return; - } - - if (viewport->pos.y < 0) - { - viewport->height += viewport->pos.y; - viewport->viewPos.y -= zoom.ApplyTo(viewport->pos.y); - viewport->pos.y = 0; - } - - eax = viewport->pos.y + viewport->height - ContextGetHeight(); - if (eax > 0) - { - viewport->height -= eax; - } - - if (viewport->height <= 0) - { - *viewport = view_copy; - return; - } - - if (DrawingEngineHasDirtyOptimisations()) - { - DrawPixelInfo& dpi = DrawingEngineGetDpi(); - ViewportShiftPixels(dpi, w, viewport, x_diff, y_diff); - } - - *viewport = view_copy; -} - -// rct2: 0x006E7A15 -static void ViewportSetUndergroundFlag(int32_t underground, WindowBase* window, Viewport* viewport) -{ - if (window->classification != WindowClass::MainWindow - || (window->classification == WindowClass::MainWindow && !window->viewport_smart_follow_sprite.IsNull())) - { - if (!underground) + if (!window->viewport_smart_follow_sprite.IsNull()) { - int32_t bit = viewport->flags & VIEWPORT_FLAG_UNDERGROUND_INSIDE; - viewport->flags &= ~VIEWPORT_FLAG_UNDERGROUND_INSIDE; - if (!bit) - return; + ViewportUpdateSmartFollowEntity(window); } - else - { - int32_t bit = viewport->flags & VIEWPORT_FLAG_UNDERGROUND_INSIDE; - viewport->flags |= VIEWPORT_FLAG_UNDERGROUND_INSIDE; - if (bit) - return; - } - window->Invalidate(); - } -} - -/** - * - * rct2: 0x006E7A3A - */ -void ViewportUpdatePosition(WindowBase* window) -{ - window->OnResize(); - - Viewport* viewport = window->viewport; - if (viewport == nullptr) - return; - - if (!window->viewport_smart_follow_sprite.IsNull()) - { - ViewportUpdateSmartFollowEntity(window); - } - - if (!window->viewport_target_sprite.IsNull()) - { - ViewportUpdateFollowSprite(window); - return; - } - - ViewportSetUndergroundFlag(0, window, viewport); - - auto viewportMidPoint = ScreenCoordsXY{ window->savedViewPos.x + viewport->ViewWidth() / 2, - window->savedViewPos.y + viewport->ViewHeight() / 2 }; - - auto mapCoord = ViewportPosToMapPos(viewportMidPoint, 0, viewport->rotation); - - // Clamp to the map minimum value - int32_t at_map_edge = 0; - if (mapCoord.x < kMapMinimumXY) - { - mapCoord.x = kMapMinimumXY; - at_map_edge = 1; - } - if (mapCoord.y < kMapMinimumXY) - { - mapCoord.y = kMapMinimumXY; - at_map_edge = 1; - } - - // Clamp to the map maximum value (scenario specific) - auto mapSizeMinus2 = GetMapSizeMinus2(); - if (mapCoord.x > mapSizeMinus2.x) - { - mapCoord.x = mapSizeMinus2.x; - at_map_edge = 1; - } - if (mapCoord.y > mapSizeMinus2.y) - { - mapCoord.y = mapSizeMinus2.y; - at_map_edge = 1; - } - - if (at_map_edge) - { - auto centreLoc = centre_2d_coordinates({ mapCoord, 0 }, viewport); - if (centreLoc.has_value()) - { - window->savedViewPos = centreLoc.value(); - } - } - - auto windowCoords = window->savedViewPos; - if (window->flags & WF_SCROLLING_TO_LOCATION) - { - // Moves the viewport if focusing in on an item - uint8_t flags = 0; - windowCoords.x -= viewport->viewPos.x; - if (windowCoords.x < 0) - { - windowCoords.x = -windowCoords.x; - flags |= 1; - } - windowCoords.y -= viewport->viewPos.y; - if (windowCoords.y < 0) - { - windowCoords.y = -windowCoords.y; - flags |= 2; - } - windowCoords.x = (windowCoords.x + 7) / 8; - windowCoords.y = (windowCoords.y + 7) / 8; - - // If we are at the final zoom position - if (!windowCoords.x && !windowCoords.y) - { - window->flags &= ~WF_SCROLLING_TO_LOCATION; - } - if (flags & 1) - { - windowCoords.x = -windowCoords.x; - } - if (flags & 2) - { - windowCoords.y = -windowCoords.y; - } - windowCoords.x += viewport->viewPos.x; - windowCoords.y += viewport->viewPos.y; - } - - ViewportMove(windowCoords, window, viewport); -} - -void ViewportUpdateFollowSprite(WindowBase* window) -{ - if (!window->viewport_target_sprite.IsNull() && window->viewport != nullptr) - { - auto* sprite = GetEntity(window->viewport_target_sprite); - if (sprite == nullptr) + + if (!window->viewport_target_sprite.IsNull()) { + ViewportUpdateFollowSprite(window); return; } - if (!(gScreenFlags & SCREEN_FLAGS_TITLE_DEMO)) + ViewportSetUndergroundFlag(0, window, viewport); + + auto viewportMidPoint = ScreenCoordsXY{ window->savedViewPos.x + viewport->ViewWidth() / 2, + window->savedViewPos.y + viewport->ViewHeight() / 2 }; + + auto mapCoord = ViewportPosToMapPos(viewportMidPoint, 0, viewport->rotation); + + // Clamp to the map minimum value + int32_t at_map_edge = 0; + if (mapCoord.x < kMapMinimumXY) { - int32_t height = (TileElementHeight({ sprite->x, sprite->y }))-16; - int32_t underground = sprite->z < height; - ViewportSetUndergroundFlag(underground, window, window->viewport); + mapCoord.x = kMapMinimumXY; + at_map_edge = 1; + } + if (mapCoord.y < kMapMinimumXY) + { + mapCoord.y = kMapMinimumXY; + at_map_edge = 1; } - auto centreLoc = centre_2d_coordinates(sprite->GetLocation(), window->viewport); - if (centreLoc.has_value()) + // Clamp to the map maximum value (scenario specific) + auto mapSizeMinus2 = GetMapSizeMinus2(); + if (mapCoord.x > mapSizeMinus2.x) { - window->savedViewPos = *centreLoc; - ViewportMove(*centreLoc, window, window->viewport); + mapCoord.x = mapSizeMinus2.x; + at_map_edge = 1; } - } -} - -void ViewportUpdateSmartFollowEntity(WindowBase* window) -{ - auto entity = TryGetEntity(window->viewport_smart_follow_sprite); - if (entity == nullptr || entity->Type == EntityType::Null) - { - window->viewport_smart_follow_sprite = EntityId::GetNull(); - window->viewport_target_sprite = EntityId::GetNull(); - return; - } - - switch (entity->Type) - { - case EntityType::Vehicle: - ViewportUpdateSmartFollowVehicle(window); - break; - - case EntityType::Guest: + if (mapCoord.y > mapSizeMinus2.y) { - auto* guest = entity->As(); - if (guest == nullptr) + mapCoord.y = mapSizeMinus2.y; + at_map_edge = 1; + } + + if (at_map_edge) + { + auto centreLoc = centre_2d_coordinates({ mapCoord, 0 }, viewport); + if (centreLoc.has_value()) + { + window->savedViewPos = centreLoc.value(); + } + } + + auto windowCoords = window->savedViewPos; + if (window->flags & WF_SCROLLING_TO_LOCATION) + { + // Moves the viewport if focusing in on an item + uint8_t flags = 0; + windowCoords.x -= viewport->viewPos.x; + if (windowCoords.x < 0) + { + windowCoords.x = -windowCoords.x; + flags |= 1; + } + windowCoords.y -= viewport->viewPos.y; + if (windowCoords.y < 0) + { + windowCoords.y = -windowCoords.y; + flags |= 2; + } + windowCoords.x = (windowCoords.x + 7) / 8; + windowCoords.y = (windowCoords.y + 7) / 8; + + // If we are at the final zoom position + if (!windowCoords.x && !windowCoords.y) + { + window->flags &= ~WF_SCROLLING_TO_LOCATION; + } + if (flags & 1) + { + windowCoords.x = -windowCoords.x; + } + if (flags & 2) + { + windowCoords.y = -windowCoords.y; + } + windowCoords.x += viewport->viewPos.x; + windowCoords.y += viewport->viewPos.y; + } + + ViewportMove(windowCoords, window, viewport); + } + + void ViewportUpdateFollowSprite(WindowBase* window) + { + if (!window->viewport_target_sprite.IsNull() && window->viewport != nullptr) + { + auto* sprite = GetEntity(window->viewport_target_sprite); + if (sprite == nullptr) { return; } - ViewportUpdateSmartFollowGuest(window, *guest); - break; - } - case EntityType::Staff: - { - auto* staff = entity->As(); - if (staff == nullptr) + + if (!(gScreenFlags & SCREEN_FLAGS_TITLE_DEMO)) { - return; + int32_t height = (TileElementHeight({ sprite->x, sprite->y }))-16; + int32_t underground = sprite->z < height; + ViewportSetUndergroundFlag(underground, window, window->viewport); } - ViewportUpdateSmartFollowStaff(window, *staff); - break; - } - default: // All other types don't need any "smart" following; steam particle, duck, money effect, etc. - window->focus = Focus(window->viewport_smart_follow_sprite); - window->viewport_target_sprite = window->viewport_smart_follow_sprite; - break; - } -} -void ViewportUpdateSmartFollowGuest(WindowBase* window, const Guest& peep) -{ - Focus focus = Focus(peep.Id); - window->viewport_target_sprite = peep.Id; - - if (peep.State == PeepState::Picked) - { - window->viewport_smart_follow_sprite = EntityId::GetNull(); - window->viewport_target_sprite = EntityId::GetNull(); - window->focus = std::nullopt; // No focus - return; - } - - bool overallFocus = true; - if (peep.State == PeepState::OnRide || peep.State == PeepState::EnteringRide - || (peep.State == PeepState::LeavingRide && peep.x == kLocationNull)) - { - auto ride = GetRide(peep.CurrentRide); - if (ride != nullptr && (ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK)) - { - auto train = GetEntity(ride->vehicles[peep.CurrentTrain]); - if (train != nullptr) + auto centreLoc = centre_2d_coordinates(sprite->GetLocation(), window->viewport); + if (centreLoc.has_value()) { - const auto car = train->GetCar(peep.CurrentCar); - if (car != nullptr) + window->savedViewPos = *centreLoc; + ViewportMove(*centreLoc, window, window->viewport); + } + } + } + + void ViewportUpdateSmartFollowEntity(WindowBase* window) + { + auto entity = TryGetEntity(window->viewport_smart_follow_sprite); + if (entity == nullptr || entity->Type == EntityType::Null) + { + window->viewport_smart_follow_sprite = EntityId::GetNull(); + window->viewport_target_sprite = EntityId::GetNull(); + return; + } + + switch (entity->Type) + { + case EntityType::Vehicle: + ViewportUpdateSmartFollowVehicle(window); + break; + + case EntityType::Guest: + { + auto* guest = entity->As(); + if (guest == nullptr) { - focus = Focus(car->Id); - overallFocus = false; - window->viewport_target_sprite = car->Id; + return; + } + ViewportUpdateSmartFollowGuest(window, *guest); + break; + } + case EntityType::Staff: + { + auto* staff = entity->As(); + if (staff == nullptr) + { + return; + } + ViewportUpdateSmartFollowStaff(window, *staff); + break; + } + default: // All other types don't need any "smart" following; steam particle, duck, money effect, etc. + window->focus = Focus(window->viewport_smart_follow_sprite); + window->viewport_target_sprite = window->viewport_smart_follow_sprite; + break; + } + } + + void ViewportUpdateSmartFollowGuest(WindowBase* window, const Guest& peep) + { + Focus focus = Focus(peep.Id); + window->viewport_target_sprite = peep.Id; + + if (peep.State == PeepState::Picked) + { + window->viewport_smart_follow_sprite = EntityId::GetNull(); + window->viewport_target_sprite = EntityId::GetNull(); + window->focus = std::nullopt; // No focus + return; + } + + bool overallFocus = true; + if (peep.State == PeepState::OnRide || peep.State == PeepState::EnteringRide + || (peep.State == PeepState::LeavingRide && peep.x == kLocationNull)) + { + auto ride = GetRide(peep.CurrentRide); + if (ride != nullptr && (ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK)) + { + auto train = GetEntity(ride->vehicles[peep.CurrentTrain]); + if (train != nullptr) + { + const auto car = train->GetCar(peep.CurrentCar); + if (car != nullptr) + { + focus = Focus(car->Id); + overallFocus = false; + window->viewport_target_sprite = car->Id; + } } } } - } - if (peep.x == kLocationNull && overallFocus) - { - auto ride = GetRide(peep.CurrentRide); - if (ride != nullptr) + if (peep.x == kLocationNull && overallFocus) { - auto xy = ride->overall_view.ToTileCentre(); - CoordsXYZ coordFocus; - coordFocus.x = xy.x; - coordFocus.y = xy.y; - coordFocus.z = TileElementHeight(xy) + (4 * kCoordsZStep); - focus = Focus(coordFocus); - window->viewport_target_sprite = EntityId::GetNull(); + auto ride = GetRide(peep.CurrentRide); + if (ride != nullptr) + { + auto xy = ride->overall_view.ToTileCentre(); + CoordsXYZ coordFocus; + coordFocus.x = xy.x; + coordFocus.y = xy.y; + coordFocus.z = TileElementHeight(xy) + (4 * kCoordsZStep); + focus = Focus(coordFocus); + window->viewport_target_sprite = EntityId::GetNull(); + } } + + window->focus = focus; } - window->focus = focus; -} - -void ViewportUpdateSmartFollowStaff(WindowBase* window, const Staff& peep) -{ - if (peep.State == PeepState::Picked) + void ViewportUpdateSmartFollowStaff(WindowBase* window, const Staff& peep) { - window->viewport_smart_follow_sprite = EntityId::GetNull(); - window->viewport_target_sprite = EntityId::GetNull(); - window->focus = std::nullopt; - return; + if (peep.State == PeepState::Picked) + { + window->viewport_smart_follow_sprite = EntityId::GetNull(); + window->viewport_target_sprite = EntityId::GetNull(); + window->focus = std::nullopt; + return; + } + + window->focus = Focus(window->viewport_smart_follow_sprite); + window->viewport_target_sprite = window->viewport_smart_follow_sprite; } - window->focus = Focus(window->viewport_smart_follow_sprite); - window->viewport_target_sprite = window->viewport_smart_follow_sprite; -} - -void ViewportUpdateSmartFollowVehicle(WindowBase* window) -{ - window->focus = Focus(window->viewport_smart_follow_sprite); - window->viewport_target_sprite = window->viewport_smart_follow_sprite; -} - -static void ViewportRotateSingleInternal(WindowBase& w, int32_t direction) -{ - auto* viewport = w.viewport; - if (viewport == nullptr) - return; - - auto windowPos = ScreenCoordsXY{ (viewport->width >> 1), (viewport->height >> 1) } + viewport->pos; - - // has something to do with checking if middle of the viewport is obstructed - Viewport* other; - auto mapXYCoords = ScreenGetMapXY(windowPos, &other); - CoordsXYZ coords{}; - - // other != viewport probably triggers on viewports in ride or guest window? - // mapXYCoords is nullopt if middle of viewport is obstructed by another window? - if (!mapXYCoords.has_value() || other != viewport) + void ViewportUpdateSmartFollowVehicle(WindowBase* window) { - auto viewPos = ScreenCoordsXY{ (viewport->ViewWidth() >> 1), (viewport->ViewHeight() >> 1) } + viewport->viewPos; - - coords = ViewportAdjustForMapHeight(viewPos, viewport->rotation); + window->focus = Focus(window->viewport_smart_follow_sprite); + window->viewport_target_sprite = window->viewport_smart_follow_sprite; } - else + + static void ViewportRotateSingleInternal(WindowBase& w, int32_t direction) { - coords.x = mapXYCoords->x; - coords.y = mapXYCoords->y; - coords.z = TileElementHeight(coords); - } - - viewport->rotation = (viewport->rotation + direction) & 3; - - auto centreLoc = centre_2d_coordinates(coords, viewport); - - if (centreLoc.has_value()) - { - w.savedViewPos = centreLoc.value(); - viewport->viewPos = *centreLoc; - } - - w.Invalidate(); - w.OnViewportRotate(); -} - -void ViewportRotateSingle(WindowBase* window, int32_t direction) -{ - ViewportRotateSingleInternal(*window, direction); -} - -void ViewportRotateAll(int32_t direction) -{ - WindowVisitEach([direction](WindowBase* w) { - auto* viewport = w->viewport; + auto* viewport = w.viewport; if (viewport == nullptr) return; - if (viewport->flags & VIEWPORT_FLAG_INDEPEDENT_ROTATION) + + auto windowPos = ScreenCoordsXY{ (viewport->width >> 1), (viewport->height >> 1) } + viewport->pos; + + // has something to do with checking if middle of the viewport is obstructed + Viewport* other; + auto mapXYCoords = ScreenGetMapXY(windowPos, &other); + CoordsXYZ coords{}; + + // other != viewport probably triggers on viewports in ride or guest window? + // mapXYCoords is nullopt if middle of viewport is obstructed by another window? + if (!mapXYCoords.has_value() || other != viewport) + { + auto viewPos = ScreenCoordsXY{ (viewport->ViewWidth() >> 1), (viewport->ViewHeight() >> 1) } + viewport->viewPos; + + coords = ViewportAdjustForMapHeight(viewPos, viewport->rotation); + } + else + { + coords.x = mapXYCoords->x; + coords.y = mapXYCoords->y; + coords.z = TileElementHeight(coords); + } + + viewport->rotation = (viewport->rotation + direction) & 3; + + auto centreLoc = centre_2d_coordinates(coords, viewport); + + if (centreLoc.has_value()) + { + w.savedViewPos = centreLoc.value(); + viewport->viewPos = *centreLoc; + } + + w.Invalidate(); + w.OnViewportRotate(); + } + + void ViewportRotateSingle(WindowBase* window, int32_t direction) + { + ViewportRotateSingleInternal(*window, direction); + } + + void ViewportRotateAll(int32_t direction) + { + WindowVisitEach([direction](WindowBase* w) { + auto* viewport = w->viewport; + if (viewport == nullptr) + return; + if (viewport->flags & VIEWPORT_FLAG_INDEPEDENT_ROTATION) + return; + ViewportRotateSingleInternal(*w, direction); + }); + } + + /** + * + * rct2: 0x00685C02 + * ax: left + * bx: top + * dx: right + * esi: viewport + * edi: dpi + * ebp: bottom + */ + void ViewportRender(DrawPixelInfo& dpi, const Viewport* viewport) + { + if (viewport->flags & VIEWPORT_FLAG_RENDERING_INHIBITED) return; - ViewportRotateSingleInternal(*w, direction); - }); -} -/** - * - * rct2: 0x00685C02 - * ax: left - * bx: top - * dx: right - * esi: viewport - * edi: dpi - * ebp: bottom - */ -void ViewportRender(DrawPixelInfo& dpi, const Viewport* viewport) -{ - if (viewport->flags & VIEWPORT_FLAG_RENDERING_INHIBITED) - return; + if (dpi.x + dpi.width <= viewport->pos.x) + return; + if (dpi.y + dpi.height <= viewport->pos.y) + return; + if (dpi.x >= viewport->pos.x + viewport->width) + return; + if (dpi.y >= viewport->pos.y + viewport->height) + return; - if (dpi.x + dpi.width <= viewport->pos.x) - return; - if (dpi.y + dpi.height <= viewport->pos.y) - return; - if (dpi.x >= viewport->pos.x + viewport->width) - return; - if (dpi.y >= viewport->pos.y + viewport->height) - return; + ViewportPaint(viewport, dpi); + } - ViewportPaint(viewport, dpi); -} - -static void ViewportFillColumn(PaintSession& session) -{ - PROFILED_FUNCTION(); - - PaintSessionGenerate(session); - PaintSessionArrange(session); -} - -static void ViewportPaintColumn(PaintSession& session) -{ - PROFILED_FUNCTION(); - - if (session.ViewFlags - & (VIEWPORT_FLAG_HIDE_VERTICAL | VIEWPORT_FLAG_HIDE_BASE | VIEWPORT_FLAG_UNDERGROUND_INSIDE - | VIEWPORT_FLAG_CLIP_VIEW) - && (~session.ViewFlags & VIEWPORT_FLAG_TRANSPARENT_BACKGROUND)) + static void ViewportFillColumn(PaintSession& session) { - uint8_t colour = COLOUR_AQUAMARINE; - if (session.ViewFlags & VIEWPORT_FLAG_HIDE_ENTITIES) + PROFILED_FUNCTION(); + + PaintSessionGenerate(session); + PaintSessionArrange(session); + } + + static void ViewportPaintColumn(PaintSession& session) + { + PROFILED_FUNCTION(); + + if (session.ViewFlags + & (VIEWPORT_FLAG_HIDE_VERTICAL | VIEWPORT_FLAG_HIDE_BASE | VIEWPORT_FLAG_UNDERGROUND_INSIDE + | VIEWPORT_FLAG_CLIP_VIEW) + && (~session.ViewFlags & VIEWPORT_FLAG_TRANSPARENT_BACKGROUND)) { - colour = COLOUR_BLACK; - } - GfxClear(session.DPI, colour); - } - - PaintDrawStructs(session); - - if (Config::Get().general.RenderWeatherGloom && !gTrackDesignSaveMode && !(session.ViewFlags & VIEWPORT_FLAG_HIDE_ENTITIES) - && !(session.ViewFlags & VIEWPORT_FLAG_HIGHLIGHT_PATH_ISSUES)) - { - ViewportPaintWeatherGloom(session.DPI); - } - - if (session.PSStringHead != nullptr) - { - PaintDrawMoneyStructs(session.DPI, session.PSStringHead); - } -} - -/** - * - * rct2: 0x00685CBF - * eax: left - * ebx: top - * edx: right - * esi: viewport - * edi: dpi - * ebp: bottom - */ -static void ViewportPaint(const Viewport* viewport, DrawPixelInfo& dpi) -{ - PROFILED_FUNCTION(); - - const int32_t offsetX = dpi.x - viewport->pos.x; - const int32_t offsetY = dpi.y - viewport->pos.y; - const int32_t worldX = viewport->zoom.ApplyInversedTo(viewport->viewPos.x) + std::max(0, offsetX); - const int32_t worldY = viewport->zoom.ApplyInversedTo(viewport->viewPos.y) + std::max(0, offsetY); - const int32_t width = std::min(viewport->pos.x + viewport->width, dpi.x + dpi.width) - std::max(viewport->pos.x, dpi.x); - const int32_t height = std::min(viewport->pos.y + viewport->height, dpi.y + dpi.height) - std::max(viewport->pos.y, dpi.y); - - DrawPixelInfo worldDpi; - worldDpi.DrawingEngine = dpi.DrawingEngine; - worldDpi.bits = dpi.bits + std::max(0, -offsetX) + std::max(0, -offsetY) * dpi.LineStride(); - worldDpi.x = worldX; - worldDpi.y = worldY; - worldDpi.width = width; - worldDpi.height = height; - worldDpi.pitch = dpi.LineStride() - worldDpi.width; - worldDpi.zoom_level = viewport->zoom; - - _paintColumns.clear(); - - bool useMultithreading = Config::Get().general.MultiThreading; - if (useMultithreading && _paintJobs == nullptr) - { - _paintJobs = std::make_unique(); - } - else if (useMultithreading == false && _paintJobs != nullptr) - { - _paintJobs.reset(); - } - - bool useParallelDrawing = false; - if (useMultithreading && (dpi.DrawingEngine->GetFlags() & DEF_PARALLEL_DRAWING)) - { - useParallelDrawing = true; - } - - const int32_t columnWidth = worldDpi.zoom_level.ApplyInversedTo(kCoordsXYStep); - const int32_t rightBorder = worldDpi.x + worldDpi.width; - const int32_t alignedX = floor2(worldDpi.x, columnWidth); - - // Generate and sort columns. - for (int32_t x = alignedX; x < rightBorder; x += columnWidth) - { - PaintSession* session = PaintSessionAlloc(worldDpi, viewport->flags, viewport->rotation); - _paintColumns.push_back(session); - - DrawPixelInfo& columnDpi = session->DPI; - if (x >= columnDpi.x) - { - const int32_t leftPitch = x - columnDpi.x; - columnDpi.width = columnDpi.width - leftPitch; - columnDpi.bits += leftPitch; - columnDpi.pitch += leftPitch; - columnDpi.x = x; + uint8_t colour = COLOUR_AQUAMARINE; + if (session.ViewFlags & VIEWPORT_FLAG_HIDE_ENTITIES) + { + colour = COLOUR_BLACK; + } + GfxClear(session.DPI, colour); } - int32_t paintRight = columnDpi.x + columnDpi.width; - if (paintRight >= x + columnWidth) + PaintDrawStructs(session); + + if (Config::Get().general.RenderWeatherGloom && !gTrackDesignSaveMode + && !(session.ViewFlags & VIEWPORT_FLAG_HIDE_ENTITIES) && !(session.ViewFlags & VIEWPORT_FLAG_HIGHLIGHT_PATH_ISSUES)) { - const int32_t rightPitch = paintRight - x - columnWidth; - paintRight -= rightPitch; - columnDpi.pitch += rightPitch; + ViewportPaintWeatherGloom(session.DPI); + } + + if (session.PSStringHead != nullptr) + { + PaintDrawMoneyStructs(session.DPI, session.PSStringHead); + } + } + + /** + * + * rct2: 0x00685CBF + * eax: left + * ebx: top + * edx: right + * esi: viewport + * edi: dpi + * ebp: bottom + */ + static void ViewportPaint(const Viewport* viewport, DrawPixelInfo& dpi) + { + PROFILED_FUNCTION(); + + const int32_t offsetX = dpi.x - viewport->pos.x; + const int32_t offsetY = dpi.y - viewport->pos.y; + const int32_t worldX = viewport->zoom.ApplyInversedTo(viewport->viewPos.x) + std::max(0, offsetX); + const int32_t worldY = viewport->zoom.ApplyInversedTo(viewport->viewPos.y) + std::max(0, offsetY); + const int32_t width = std::min(viewport->pos.x + viewport->width, dpi.x + dpi.width) - std::max(viewport->pos.x, dpi.x); + const int32_t height = std::min(viewport->pos.y + viewport->height, dpi.y + dpi.height) + - std::max(viewport->pos.y, dpi.y); + + DrawPixelInfo worldDpi; + worldDpi.DrawingEngine = dpi.DrawingEngine; + worldDpi.bits = dpi.bits + std::max(0, -offsetX) + std::max(0, -offsetY) * dpi.LineStride(); + worldDpi.x = worldX; + worldDpi.y = worldY; + worldDpi.width = width; + worldDpi.height = height; + worldDpi.pitch = dpi.LineStride() - worldDpi.width; + worldDpi.zoom_level = viewport->zoom; + + _paintColumns.clear(); + + bool useMultithreading = Config::Get().general.MultiThreading; + if (useMultithreading && _paintJobs == nullptr) + { + _paintJobs = std::make_unique(); + } + else if (useMultithreading == false && _paintJobs != nullptr) + { + _paintJobs.reset(); + } + + bool useParallelDrawing = false; + if (useMultithreading && (dpi.DrawingEngine->GetFlags() & DEF_PARALLEL_DRAWING)) + { + useParallelDrawing = true; + } + + const int32_t columnWidth = worldDpi.zoom_level.ApplyInversedTo(kCoordsXYStep); + const int32_t rightBorder = worldDpi.x + worldDpi.width; + const int32_t alignedX = floor2(worldDpi.x, columnWidth); + + // Generate and sort columns. + for (int32_t x = alignedX; x < rightBorder; x += columnWidth) + { + PaintSession* session = PaintSessionAlloc(worldDpi, viewport->flags, viewport->rotation); + _paintColumns.push_back(session); + + DrawPixelInfo& columnDpi = session->DPI; + if (x >= columnDpi.x) + { + const int32_t leftPitch = x - columnDpi.x; + columnDpi.width = columnDpi.width - leftPitch; + columnDpi.bits += leftPitch; + columnDpi.pitch += leftPitch; + columnDpi.x = x; + } + + int32_t paintRight = columnDpi.x + columnDpi.width; + if (paintRight >= x + columnWidth) + { + const int32_t rightPitch = paintRight - x - columnWidth; + paintRight -= rightPitch; + columnDpi.pitch += rightPitch; + } + columnDpi.width = paintRight - columnDpi.x; + + if (useMultithreading) + { + _paintJobs->AddTask([session]() -> void { ViewportFillColumn(*session); }); + } + else + { + ViewportFillColumn(*session); + } } - columnDpi.width = paintRight - columnDpi.x; if (useMultithreading) { - _paintJobs->AddTask([session]() -> void { ViewportFillColumn(*session); }); + _paintJobs->Join(); } - else + + // Paint columns. + for (auto* session : _paintColumns) { - ViewportFillColumn(*session); + if (useParallelDrawing) + { + _paintJobs->AddTask([session]() -> void { ViewportPaintColumn(*session); }); + } + else + { + ViewportPaintColumn(*session); + } } - } - - if (useMultithreading) - { - _paintJobs->Join(); - } - - // Paint columns. - for (auto* session : _paintColumns) - { if (useParallelDrawing) { - _paintJobs->AddTask([session]() -> void { ViewportPaintColumn(*session); }); + _paintJobs->Join(); + } + + // Release resources. + for (auto* session : _paintColumns) + { + PaintSessionFree(session); + } + } + + static void ViewportPaintWeatherGloom(DrawPixelInfo& dpi) + { + auto paletteId = ClimateGetWeatherGloomPaletteId(GetGameState().ClimateCurrent); + if (paletteId != FilterPaletteID::PaletteNull) + { + auto x = dpi.x; + auto y = dpi.y; + auto w = dpi.width; + auto h = dpi.height; + GfxFilterRect(dpi, ScreenRect(x, y, x + w, y + h), paletteId); + } + } + + /** + * + * rct2: 0x0068958D + */ + std::optional ScreenPosToMapPos(const ScreenCoordsXY& screenCoords, int32_t* direction) + { + auto mapCoords = ScreenGetMapXY(screenCoords, nullptr); + if (!mapCoords.has_value()) + return std::nullopt; + + int32_t my_direction; + int32_t dist_from_centre_x = abs(mapCoords->x % 32); + int32_t dist_from_centre_y = abs(mapCoords->y % 32); + if (dist_from_centre_x > 8 && dist_from_centre_x < 24 && dist_from_centre_y > 8 && dist_from_centre_y < 24) + { + my_direction = 4; } else { - ViewportPaintColumn(*session); - } - } - if (useParallelDrawing) - { - _paintJobs->Join(); - } - - // Release resources. - for (auto* session : _paintColumns) - { - PaintSessionFree(session); - } -} - -static void ViewportPaintWeatherGloom(DrawPixelInfo& dpi) -{ - auto paletteId = ClimateGetWeatherGloomPaletteId(GetGameState().ClimateCurrent); - if (paletteId != FilterPaletteID::PaletteNull) - { - auto x = dpi.x; - auto y = dpi.y; - auto w = dpi.width; - auto h = dpi.height; - GfxFilterRect(dpi, ScreenRect(x, y, x + w, y + h), paletteId); - } -} - -/** - * - * rct2: 0x0068958D - */ -std::optional ScreenPosToMapPos(const ScreenCoordsXY& screenCoords, int32_t* direction) -{ - auto mapCoords = ScreenGetMapXY(screenCoords, nullptr); - if (!mapCoords.has_value()) - return std::nullopt; - - int32_t my_direction; - int32_t dist_from_centre_x = abs(mapCoords->x % 32); - int32_t dist_from_centre_y = abs(mapCoords->y % 32); - if (dist_from_centre_x > 8 && dist_from_centre_x < 24 && dist_from_centre_y > 8 && dist_from_centre_y < 24) - { - my_direction = 4; - } - else - { - auto mod_x = mapCoords->x & 0x1F; - auto mod_y = mapCoords->y & 0x1F; - if (mod_x <= 16) - { - if (mod_y < 16) + auto mod_x = mapCoords->x & 0x1F; + auto mod_y = mapCoords->y & 0x1F; + if (mod_x <= 16) { - my_direction = 2; - } - else - { - my_direction = 3; - } - } - else - { - if (mod_y < 16) - { - my_direction = 1; - } - else - { - my_direction = 0; - } - } - } - - if (direction != nullptr) - *direction = my_direction; - return { mapCoords->ToTileStart() }; -} - -[[nodiscard]] ScreenCoordsXY Viewport::ScreenToViewportCoord(const ScreenCoordsXY& screenCoords) const -{ - ScreenCoordsXY ret; - ret.x = (zoom.ApplyTo(screenCoords.x - pos.x)) + viewPos.x; - ret.y = (zoom.ApplyTo(screenCoords.y - pos.y)) + viewPos.y; - return ret; -} - -void Viewport::Invalidate() const -{ - ViewportInvalidate(this, { viewPos, viewPos + ScreenCoordsXY{ ViewWidth(), ViewHeight() } }); -} - -CoordsXY ViewportPosToMapPos(const ScreenCoordsXY& coords, int32_t z, uint8_t rotation) -{ - // Reverse of Translate3DTo2DWithZ - CoordsXY ret = { coords.y - coords.x / 2 + z, coords.y + coords.x / 2 + z }; - auto inverseRotation = DirectionFlipXAxis(rotation); - return ret.Rotate(inverseRotation); -} - -/** - * - * rct2: 0x00664689 - */ -void ShowGridlines() -{ - if (gShowGridLinesRefCount == 0) - { - WindowBase* mainWindow = WindowGetMain(); - if (mainWindow != nullptr) - { - if (!(mainWindow->viewport->flags & VIEWPORT_FLAG_GRIDLINES)) - { - mainWindow->viewport->flags |= VIEWPORT_FLAG_GRIDLINES; - mainWindow->Invalidate(); - } - } - } - gShowGridLinesRefCount++; -} - -/** - * - * rct2: 0x006646B4 - */ -void HideGridlines() -{ - if (gShowGridLinesRefCount > 0) - gShowGridLinesRefCount--; - - if (gShowGridLinesRefCount == 0) - { - WindowBase* mainWindow = WindowGetMain(); - if (mainWindow != nullptr) - { - if (!Config::Get().general.AlwaysShowGridlines) - { - mainWindow->viewport->flags &= ~VIEWPORT_FLAG_GRIDLINES; - mainWindow->Invalidate(); - } - } - } -} - -/** - * - * rct2: 0x00664E8E - */ -void ShowLandRights() -{ - if (gShowLandRightsRefCount == 0) - { - WindowBase* mainWindow = WindowGetMain(); - if (mainWindow != nullptr) - { - if (!(mainWindow->viewport->flags & VIEWPORT_FLAG_LAND_OWNERSHIP)) - { - mainWindow->viewport->flags |= VIEWPORT_FLAG_LAND_OWNERSHIP; - mainWindow->Invalidate(); - } - } - } - gShowLandRightsRefCount++; -} - -/** - * - * rct2: 0x00664EB9 - */ -void HideLandRights() -{ - if (gShowLandRightsRefCount > 0) - gShowLandRightsRefCount--; - - if (gShowLandRightsRefCount == 0) - { - WindowBase* mainWindow = WindowGetMain(); - if (mainWindow != nullptr) - { - if (mainWindow->viewport->flags & VIEWPORT_FLAG_LAND_OWNERSHIP) - { - mainWindow->viewport->flags &= ~VIEWPORT_FLAG_LAND_OWNERSHIP; - mainWindow->Invalidate(); - } - } - } -} - -/** - * - * rct2: 0x00664EDD - */ -void ShowConstructionRights() -{ - if (gShowConstructionRightsRefCount == 0) - { - WindowBase* mainWindow = WindowGetMain(); - if (mainWindow != nullptr) - { - if (!(mainWindow->viewport->flags & VIEWPORT_FLAG_CONSTRUCTION_RIGHTS)) - { - mainWindow->viewport->flags |= VIEWPORT_FLAG_CONSTRUCTION_RIGHTS; - mainWindow->Invalidate(); - } - } - } - gShowConstructionRightsRefCount++; -} - -/** - * - * rct2: 0x00664F08 - */ -void HideConstructionRights() -{ - if (gShowConstructionRightsRefCount > 0) - gShowConstructionRightsRefCount--; - - if (gShowConstructionRightsRefCount == 0) - { - WindowBase* mainWindow = WindowGetMain(); - if (mainWindow != nullptr) - { - if (mainWindow->viewport->flags & VIEWPORT_FLAG_CONSTRUCTION_RIGHTS) - { - mainWindow->viewport->flags &= ~VIEWPORT_FLAG_CONSTRUCTION_RIGHTS; - mainWindow->Invalidate(); - } - } - } -} - -/** - * - * rct2: 0x006CB70A - */ -void ViewportSetVisibility(ViewportVisibility mode) -{ - WindowBase* window = WindowGetMain(); - - if (window != nullptr) - { - Viewport* vp = window->viewport; - uint32_t invalidate = 0; - - switch (mode) - { - case ViewportVisibility::Default: - { // Set all these flags to 0, and invalidate if any were active - uint32_t mask = VIEWPORT_FLAG_UNDERGROUND_INSIDE | VIEWPORT_FLAG_HIDE_RIDES | VIEWPORT_FLAG_HIDE_SCENERY - | VIEWPORT_FLAG_HIDE_PATHS | VIEWPORT_FLAG_LAND_HEIGHTS | VIEWPORT_FLAG_TRACK_HEIGHTS - | VIEWPORT_FLAG_PATH_HEIGHTS | VIEWPORT_FLAG_HIDE_GUESTS | VIEWPORT_FLAG_HIDE_STAFF - | VIEWPORT_FLAG_HIDE_BASE | VIEWPORT_FLAG_HIDE_VERTICAL | VIEWPORT_FLAG_HIDE_VEHICLES - | VIEWPORT_FLAG_HIDE_SUPPORTS | VIEWPORT_FLAG_HIDE_VEGETATION; - - invalidate += vp->flags & mask; - vp->flags &= ~mask; - break; - } - case ViewportVisibility::UndergroundViewOn: // 6CB79D - case ViewportVisibility::UndergroundViewGhostOn: // 6CB7C4 - // Set underground on, invalidate if it was off - invalidate += !(vp->flags & VIEWPORT_FLAG_UNDERGROUND_INSIDE); - vp->flags |= VIEWPORT_FLAG_UNDERGROUND_INSIDE; - break; - case ViewportVisibility::TrackHeights: // 6CB7EB - // Set track heights on, invalidate if off - invalidate += !(vp->flags & VIEWPORT_FLAG_TRACK_HEIGHTS); - vp->flags |= VIEWPORT_FLAG_TRACK_HEIGHTS; - break; - case ViewportVisibility::UndergroundViewOff: // 6CB7B1 - case ViewportVisibility::UndergroundViewGhostOff: // 6CB7D8 - // Set underground off, invalidate if it was on - invalidate += vp->flags & VIEWPORT_FLAG_UNDERGROUND_INSIDE; - vp->flags &= ~(static_cast(VIEWPORT_FLAG_UNDERGROUND_INSIDE)); - break; - } - if (invalidate != 0) - window->Invalidate(); - } -} - -static bool IsCursorIdVegetation(CursorID cursor) -{ - switch (cursor) - { - case CursorID::TreeDown: - case CursorID::FlowerDown: - return true; - default: - return false; - } -} - -static bool IsTileElementVegetation(const TileElement* tileElement) -{ - switch (tileElement->GetType()) - { - case TileElementType::SmallScenery: - { - auto sceneryItem = tileElement->AsSmallScenery(); - auto sceneryEntry = sceneryItem->GetEntry(); - if (sceneryEntry != nullptr - && (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_IS_TREE) || IsCursorIdVegetation(sceneryEntry->tool_id))) - { - return true; - } - break; - } - case TileElementType::LargeScenery: - { - auto sceneryItem = tileElement->AsLargeScenery(); - auto sceneryEntry = sceneryItem->GetEntry(); - if (sceneryEntry != nullptr && IsCursorIdVegetation(sceneryEntry->tool_id)) - { - return true; - } - break; - } - case TileElementType::Wall: - { - auto sceneryItem = tileElement->AsWall(); - auto sceneryEntry = sceneryItem->GetEntry(); - if (sceneryEntry != nullptr && IsCursorIdVegetation(sceneryEntry->tool_id)) - { - return true; - } - break; - } - default: - break; - } - return false; -} - -VisibilityKind GetPaintStructVisibility(const PaintStruct* ps, uint32_t viewFlags) -{ - switch (ps->InteractionItem) - { - case ViewportInteractionItem::Entity: - if (ps->Entity != nullptr) - { - switch (ps->Entity->Type) + if (mod_y < 16) { - case EntityType::Vehicle: - { - if (viewFlags & VIEWPORT_FLAG_HIDE_VEHICLES) - { - return (viewFlags & VIEWPORT_FLAG_INVISIBLE_VEHICLES) ? VisibilityKind::Hidden - : VisibilityKind::Partial; - } - // Rides without track can technically have a 'vehicle': - // these should be hidden if 'hide rides' is enabled - if (viewFlags & VIEWPORT_FLAG_HIDE_RIDES) - { - auto vehicle = ps->Entity->As(); - if (vehicle == nullptr) - break; - - auto ride = vehicle->GetRide(); - if (ride != nullptr && !ride->GetRideTypeDescriptor().HasFlag(RtdFlag::hasTrack)) - { - return (viewFlags & VIEWPORT_FLAG_INVISIBLE_RIDES) ? VisibilityKind::Hidden - : VisibilityKind::Partial; - } - } - break; - } - case EntityType::Guest: - if (viewFlags & VIEWPORT_FLAG_HIDE_GUESTS) - { - return VisibilityKind::Hidden; - } - break; - case EntityType::Staff: - if (viewFlags & VIEWPORT_FLAG_HIDE_STAFF) - { - return VisibilityKind::Hidden; - } - break; - default: - break; - } - } - break; - case ViewportInteractionItem::Ride: - if (viewFlags & VIEWPORT_FLAG_HIDE_RIDES) - { - return (viewFlags & VIEWPORT_FLAG_INVISIBLE_RIDES) ? VisibilityKind::Hidden : VisibilityKind::Partial; - } - break; - case ViewportInteractionItem::Footpath: - case ViewportInteractionItem::PathAddition: - case ViewportInteractionItem::Banner: - if (viewFlags & VIEWPORT_FLAG_HIDE_PATHS) - { - return (viewFlags & VIEWPORT_FLAG_INVISIBLE_PATHS) ? VisibilityKind::Hidden : VisibilityKind::Partial; - } - break; - case ViewportInteractionItem::Scenery: - case ViewportInteractionItem::LargeScenery: - case ViewportInteractionItem::Wall: - if (ps->Element != nullptr) - { - if (IsTileElementVegetation(ps->Element)) - { - if (viewFlags & VIEWPORT_FLAG_HIDE_VEGETATION) - { - return (viewFlags & VIEWPORT_FLAG_INVISIBLE_VEGETATION) ? VisibilityKind::Hidden - : VisibilityKind::Partial; - } + my_direction = 2; } else { - if (viewFlags & VIEWPORT_FLAG_HIDE_SCENERY) - { - return (viewFlags & VIEWPORT_FLAG_INVISIBLE_SCENERY) ? VisibilityKind::Hidden : VisibilityKind::Partial; - } + my_direction = 3; } } - if (ps->InteractionItem == ViewportInteractionItem::Wall && (viewFlags & VIEWPORT_FLAG_UNDERGROUND_INSIDE)) + else { - return VisibilityKind::Partial; + if (mod_y < 16) + { + my_direction = 1; + } + else + { + my_direction = 0; + } } - break; - default: - break; - } - return VisibilityKind::Visible; -} + } -/** - * Checks if a PaintStruct sprite type is in the filter mask. - */ -static bool PSInteractionTypeIsInFilter(PaintStruct* ps, uint16_t filter) -{ - if (ps->InteractionItem != ViewportInteractionItem::None && ps->InteractionItem != ViewportInteractionItem::Label - && ps->InteractionItem <= ViewportInteractionItem::Banner) + if (direction != nullptr) + *direction = my_direction; + return { mapCoords->ToTileStart() }; + } + + [[nodiscard]] ScreenCoordsXY Viewport::ScreenToViewportCoord(const ScreenCoordsXY& screenCoords) const { - auto mask = EnumToFlag(ps->InteractionItem); - if (filter & mask) + ScreenCoordsXY ret; + ret.x = (zoom.ApplyTo(screenCoords.x - pos.x)) + viewPos.x; + ret.y = (zoom.ApplyTo(screenCoords.y - pos.y)) + viewPos.y; + return ret; + } + + void Viewport::Invalidate() const + { + ViewportInvalidate(this, { viewPos, viewPos + ScreenCoordsXY{ ViewWidth(), ViewHeight() } }); + } + + CoordsXY ViewportPosToMapPos(const ScreenCoordsXY& coords, int32_t z, uint8_t rotation) + { + // Reverse of Translate3DTo2DWithZ + CoordsXY ret = { coords.y - coords.x / 2 + z, coords.y + coords.x / 2 + z }; + auto inverseRotation = DirectionFlipXAxis(rotation); + return ret.Rotate(inverseRotation); + } + + /** + * + * rct2: 0x00664689 + */ + void ShowGridlines() + { + if (gShowGridLinesRefCount == 0) { - return true; + WindowBase* mainWindow = WindowGetMain(); + if (mainWindow != nullptr) + { + if (!(mainWindow->viewport->flags & VIEWPORT_FLAG_GRIDLINES)) + { + mainWindow->viewport->flags |= VIEWPORT_FLAG_GRIDLINES; + mainWindow->Invalidate(); + } + } + } + gShowGridLinesRefCount++; + } + + /** + * + * rct2: 0x006646B4 + */ + void HideGridlines() + { + if (gShowGridLinesRefCount > 0) + gShowGridLinesRefCount--; + + if (gShowGridLinesRefCount == 0) + { + WindowBase* mainWindow = WindowGetMain(); + if (mainWindow != nullptr) + { + if (!Config::Get().general.AlwaysShowGridlines) + { + mainWindow->viewport->flags &= ~VIEWPORT_FLAG_GRIDLINES; + mainWindow->Invalidate(); + } + } } } - return false; -} -/** - * rct2: 0x00679236, 0x00679662, 0x00679B0D, 0x00679FF1 - */ -static bool IsPixelPresentBMP( - const uint32_t imageType, const G1Element* g1, const int32_t x, const int32_t y, const PaletteMap& paletteMap) -{ - uint8_t* index = g1->offset + (y * g1->width) + x; - - // Needs investigation as it has no consideration for pure BMP maps. - if (!(g1->flags & G1_FLAG_HAS_TRANSPARENCY)) + /** + * + * rct2: 0x00664E8E + */ + void ShowLandRights() { + if (gShowLandRightsRefCount == 0) + { + WindowBase* mainWindow = WindowGetMain(); + if (mainWindow != nullptr) + { + if (!(mainWindow->viewport->flags & VIEWPORT_FLAG_LAND_OWNERSHIP)) + { + mainWindow->viewport->flags |= VIEWPORT_FLAG_LAND_OWNERSHIP; + mainWindow->Invalidate(); + } + } + } + gShowLandRightsRefCount++; + } + + /** + * + * rct2: 0x00664EB9 + */ + void HideLandRights() + { + if (gShowLandRightsRefCount > 0) + gShowLandRightsRefCount--; + + if (gShowLandRightsRefCount == 0) + { + WindowBase* mainWindow = WindowGetMain(); + if (mainWindow != nullptr) + { + if (mainWindow->viewport->flags & VIEWPORT_FLAG_LAND_OWNERSHIP) + { + mainWindow->viewport->flags &= ~VIEWPORT_FLAG_LAND_OWNERSHIP; + mainWindow->Invalidate(); + } + } + } + } + + /** + * + * rct2: 0x00664EDD + */ + void ShowConstructionRights() + { + if (gShowConstructionRightsRefCount == 0) + { + WindowBase* mainWindow = WindowGetMain(); + if (mainWindow != nullptr) + { + if (!(mainWindow->viewport->flags & VIEWPORT_FLAG_CONSTRUCTION_RIGHTS)) + { + mainWindow->viewport->flags |= VIEWPORT_FLAG_CONSTRUCTION_RIGHTS; + mainWindow->Invalidate(); + } + } + } + gShowConstructionRightsRefCount++; + } + + /** + * + * rct2: 0x00664F08 + */ + void HideConstructionRights() + { + if (gShowConstructionRightsRefCount > 0) + gShowConstructionRightsRefCount--; + + if (gShowConstructionRightsRefCount == 0) + { + WindowBase* mainWindow = WindowGetMain(); + if (mainWindow != nullptr) + { + if (mainWindow->viewport->flags & VIEWPORT_FLAG_CONSTRUCTION_RIGHTS) + { + mainWindow->viewport->flags &= ~VIEWPORT_FLAG_CONSTRUCTION_RIGHTS; + mainWindow->Invalidate(); + } + } + } + } + + /** + * + * rct2: 0x006CB70A + */ + void ViewportSetVisibility(ViewportVisibility mode) + { + WindowBase* window = WindowGetMain(); + + if (window != nullptr) + { + Viewport* vp = window->viewport; + uint32_t invalidate = 0; + + switch (mode) + { + case ViewportVisibility::Default: + { // Set all these flags to 0, and invalidate if any were active + uint32_t mask = VIEWPORT_FLAG_UNDERGROUND_INSIDE | VIEWPORT_FLAG_HIDE_RIDES | VIEWPORT_FLAG_HIDE_SCENERY + | VIEWPORT_FLAG_HIDE_PATHS | VIEWPORT_FLAG_LAND_HEIGHTS | VIEWPORT_FLAG_TRACK_HEIGHTS + | VIEWPORT_FLAG_PATH_HEIGHTS | VIEWPORT_FLAG_HIDE_GUESTS | VIEWPORT_FLAG_HIDE_STAFF + | VIEWPORT_FLAG_HIDE_BASE | VIEWPORT_FLAG_HIDE_VERTICAL | VIEWPORT_FLAG_HIDE_VEHICLES + | VIEWPORT_FLAG_HIDE_SUPPORTS | VIEWPORT_FLAG_HIDE_VEGETATION; + + invalidate += vp->flags & mask; + vp->flags &= ~mask; + break; + } + case ViewportVisibility::UndergroundViewOn: // 6CB79D + case ViewportVisibility::UndergroundViewGhostOn: // 6CB7C4 + // Set underground on, invalidate if it was off + invalidate += !(vp->flags & VIEWPORT_FLAG_UNDERGROUND_INSIDE); + vp->flags |= VIEWPORT_FLAG_UNDERGROUND_INSIDE; + break; + case ViewportVisibility::TrackHeights: // 6CB7EB + // Set track heights on, invalidate if off + invalidate += !(vp->flags & VIEWPORT_FLAG_TRACK_HEIGHTS); + vp->flags |= VIEWPORT_FLAG_TRACK_HEIGHTS; + break; + case ViewportVisibility::UndergroundViewOff: // 6CB7B1 + case ViewportVisibility::UndergroundViewGhostOff: // 6CB7D8 + // Set underground off, invalidate if it was on + invalidate += vp->flags & VIEWPORT_FLAG_UNDERGROUND_INSIDE; + vp->flags &= ~(static_cast(VIEWPORT_FLAG_UNDERGROUND_INSIDE)); + break; + } + if (invalidate != 0) + window->Invalidate(); + } + } + + static bool IsCursorIdVegetation(CursorID cursor) + { + switch (cursor) + { + case CursorID::TreeDown: + case CursorID::FlowerDown: + return true; + default: + return false; + } + } + + static bool IsTileElementVegetation(const TileElement* tileElement) + { + switch (tileElement->GetType()) + { + case TileElementType::SmallScenery: + { + auto sceneryItem = tileElement->AsSmallScenery(); + auto sceneryEntry = sceneryItem->GetEntry(); + if (sceneryEntry != nullptr + && (sceneryEntry->HasFlag(SMALL_SCENERY_FLAG_IS_TREE) || IsCursorIdVegetation(sceneryEntry->tool_id))) + { + return true; + } + break; + } + case TileElementType::LargeScenery: + { + auto sceneryItem = tileElement->AsLargeScenery(); + auto sceneryEntry = sceneryItem->GetEntry(); + if (sceneryEntry != nullptr && IsCursorIdVegetation(sceneryEntry->tool_id)) + { + return true; + } + break; + } + case TileElementType::Wall: + { + auto sceneryItem = tileElement->AsWall(); + auto sceneryEntry = sceneryItem->GetEntry(); + if (sceneryEntry != nullptr && IsCursorIdVegetation(sceneryEntry->tool_id)) + { + return true; + } + break; + } + default: + break; + } return false; } - if (imageType & IMAGE_TYPE_REMAP) + VisibilityKind GetPaintStructVisibility(const PaintStruct* ps, uint32_t viewFlags) { - return paletteMap[*index] != 0; + switch (ps->InteractionItem) + { + case ViewportInteractionItem::Entity: + if (ps->Entity != nullptr) + { + switch (ps->Entity->Type) + { + case EntityType::Vehicle: + { + if (viewFlags & VIEWPORT_FLAG_HIDE_VEHICLES) + { + return (viewFlags & VIEWPORT_FLAG_INVISIBLE_VEHICLES) ? VisibilityKind::Hidden + : VisibilityKind::Partial; + } + // Rides without track can technically have a 'vehicle': + // these should be hidden if 'hide rides' is enabled + if (viewFlags & VIEWPORT_FLAG_HIDE_RIDES) + { + auto vehicle = ps->Entity->As(); + if (vehicle == nullptr) + break; + + auto ride = vehicle->GetRide(); + if (ride != nullptr && !ride->GetRideTypeDescriptor().HasFlag(RtdFlag::hasTrack)) + { + return (viewFlags & VIEWPORT_FLAG_INVISIBLE_RIDES) ? VisibilityKind::Hidden + : VisibilityKind::Partial; + } + } + break; + } + case EntityType::Guest: + if (viewFlags & VIEWPORT_FLAG_HIDE_GUESTS) + { + return VisibilityKind::Hidden; + } + break; + case EntityType::Staff: + if (viewFlags & VIEWPORT_FLAG_HIDE_STAFF) + { + return VisibilityKind::Hidden; + } + break; + default: + break; + } + } + break; + case ViewportInteractionItem::Ride: + if (viewFlags & VIEWPORT_FLAG_HIDE_RIDES) + { + return (viewFlags & VIEWPORT_FLAG_INVISIBLE_RIDES) ? VisibilityKind::Hidden : VisibilityKind::Partial; + } + break; + case ViewportInteractionItem::Footpath: + case ViewportInteractionItem::PathAddition: + case ViewportInteractionItem::Banner: + if (viewFlags & VIEWPORT_FLAG_HIDE_PATHS) + { + return (viewFlags & VIEWPORT_FLAG_INVISIBLE_PATHS) ? VisibilityKind::Hidden : VisibilityKind::Partial; + } + break; + case ViewportInteractionItem::Scenery: + case ViewportInteractionItem::LargeScenery: + case ViewportInteractionItem::Wall: + if (ps->Element != nullptr) + { + if (IsTileElementVegetation(ps->Element)) + { + if (viewFlags & VIEWPORT_FLAG_HIDE_VEGETATION) + { + return (viewFlags & VIEWPORT_FLAG_INVISIBLE_VEGETATION) ? VisibilityKind::Hidden + : VisibilityKind::Partial; + } + } + else + { + if (viewFlags & VIEWPORT_FLAG_HIDE_SCENERY) + { + return (viewFlags & VIEWPORT_FLAG_INVISIBLE_SCENERY) ? VisibilityKind::Hidden + : VisibilityKind::Partial; + } + } + } + if (ps->InteractionItem == ViewportInteractionItem::Wall && (viewFlags & VIEWPORT_FLAG_UNDERGROUND_INSIDE)) + { + return VisibilityKind::Partial; + } + break; + default: + break; + } + return VisibilityKind::Visible; } - if (imageType & IMAGE_TYPE_TRANSPARENT) + /** + * Checks if a PaintStruct sprite type is in the filter mask. + */ + static bool PSInteractionTypeIsInFilter(PaintStruct* ps, uint16_t filter) { + if (ps->InteractionItem != ViewportInteractionItem::None && ps->InteractionItem != ViewportInteractionItem::Label + && ps->InteractionItem <= ViewportInteractionItem::Banner) + { + auto mask = EnumToFlag(ps->InteractionItem); + if (filter & mask) + { + return true; + } + } return false; } - return (*index != 0); -} - -/** - * rct2: 0x0067933B, 0x00679788, 0x00679C4A, 0x0067A117 - */ -static bool IsPixelPresentRLE(const uint8_t* imgData, const int32_t x, const int32_t y) -{ - uint16_t lineOffset; - std::memcpy(&lineOffset, &imgData[y * sizeof(uint16_t)], sizeof(uint16_t)); - const uint8_t* data8 = imgData + lineOffset; - - bool lastDataLine = false; - while (!lastDataLine) + /** + * rct2: 0x00679236, 0x00679662, 0x00679B0D, 0x00679FF1 + */ + static bool IsPixelPresentBMP( + const uint32_t imageType, const G1Element* g1, const int32_t x, const int32_t y, const PaletteMap& paletteMap) { - int32_t numPixels = *data8++; - uint8_t pixelRunStart = *data8++; - lastDataLine = numPixels & 0x80; - numPixels &= 0x7F; - data8 += numPixels; + uint8_t* index = g1->offset + (y * g1->width) + x; - if (pixelRunStart <= x && x < pixelRunStart + numPixels) - return true; - } - return false; -} - -/** - * rct2: 0x00679074 - */ -static bool IsSpriteInteractedWithPaletteSet( - DrawPixelInfo& dpi, ImageId imageId, const ScreenCoordsXY& coords, const PaletteMap& paletteMap, const uint8_t imageType) -{ - PROFILED_FUNCTION(); - - const G1Element* g1 = GfxGetG1Element(imageId); - if (g1 == nullptr) - { - return false; - } - - ZoomLevel zoomLevel = dpi.zoom_level; - ScreenCoordsXY interactionPoint{ dpi.WorldX(), dpi.WorldY() }; - ScreenCoordsXY origin = coords; - - if (dpi.zoom_level > ZoomLevel{ 0 }) - { - if (g1->flags & G1_FLAG_NO_ZOOM_DRAW) + // Needs investigation as it has no consideration for pure BMP maps. + if (!(g1->flags & G1_FLAG_HAS_TRANSPARENCY)) { return false; } - while (g1->flags & G1_FLAG_HAS_ZOOM_SPRITE && zoomLevel > ZoomLevel{ 0 }) + if (imageType & IMAGE_TYPE_REMAP) { - imageId = imageId.WithIndex(imageId.GetIndex() - g1->zoomed_offset); - g1 = GfxGetG1Element(imageId); - if (g1 == nullptr || g1->flags & G1_FLAG_NO_ZOOM_DRAW) - { - return false; - } - zoomLevel = zoomLevel - 1; - interactionPoint.x >>= 1; - interactionPoint.y >>= 1; - origin.x >>= 1; - origin.y >>= 1; + return paletteMap[*index] != 0; } + + if (imageType & IMAGE_TYPE_TRANSPARENT) + { + return false; + } + + return (*index != 0); } - origin.x += g1->x_offset; - origin.y += g1->y_offset; - interactionPoint -= origin; - - if (interactionPoint.x < 0 || interactionPoint.y < 0 || interactionPoint.x >= g1->width || interactionPoint.y >= g1->height) + /** + * rct2: 0x0067933B, 0x00679788, 0x00679C4A, 0x0067A117 + */ + static bool IsPixelPresentRLE(const uint8_t* imgData, const int32_t x, const int32_t y) { + uint16_t lineOffset; + std::memcpy(&lineOffset, &imgData[y * sizeof(uint16_t)], sizeof(uint16_t)); + const uint8_t* data8 = imgData + lineOffset; + + bool lastDataLine = false; + while (!lastDataLine) + { + int32_t numPixels = *data8++; + uint8_t pixelRunStart = *data8++; + lastDataLine = numPixels & 0x80; + numPixels &= 0x7F; + data8 += numPixels; + + if (pixelRunStart <= x && x < pixelRunStart + numPixels) + return true; + } return false; } - if (g1->flags & G1_FLAG_RLE_COMPRESSION) + /** + * rct2: 0x00679074 + */ + static bool IsSpriteInteractedWithPaletteSet( + DrawPixelInfo& dpi, ImageId imageId, const ScreenCoordsXY& coords, const PaletteMap& paletteMap, + const uint8_t imageType) { - return IsPixelPresentRLE(g1->offset, interactionPoint.x, interactionPoint.y); - } + PROFILED_FUNCTION(); - if (!(g1->flags & G1_FLAG_1)) - { - return IsPixelPresentBMP(imageType, g1, interactionPoint.x, interactionPoint.y, paletteMap); - } - - Guard::Assert(false, "Invalid image type encountered."); - return false; -} - -/** - * - * rct2: 0x00679023 - */ - -static bool IsSpriteInteractedWith(DrawPixelInfo& dpi, ImageId imageId, const ScreenCoordsXY& coords) -{ - PROFILED_FUNCTION(); - - auto paletteMap = PaletteMap::GetDefault(); - uint8_t imageType; - if (imageId.HasPrimary() || imageId.IsRemap()) - { - imageType = IMAGE_TYPE_REMAP; - uint8_t paletteIndex; - if (imageId.HasSecondary()) + const G1Element* g1 = GfxGetG1Element(imageId); + if (g1 == nullptr) { - paletteIndex = imageId.GetPrimary(); + return false; + } + + ZoomLevel zoomLevel = dpi.zoom_level; + ScreenCoordsXY interactionPoint{ dpi.WorldX(), dpi.WorldY() }; + ScreenCoordsXY origin = coords; + + if (dpi.zoom_level > ZoomLevel{ 0 }) + { + if (g1->flags & G1_FLAG_NO_ZOOM_DRAW) + { + return false; + } + + while (g1->flags & G1_FLAG_HAS_ZOOM_SPRITE && zoomLevel > ZoomLevel{ 0 }) + { + imageId = imageId.WithIndex(imageId.GetIndex() - g1->zoomed_offset); + g1 = GfxGetG1Element(imageId); + if (g1 == nullptr || g1->flags & G1_FLAG_NO_ZOOM_DRAW) + { + return false; + } + zoomLevel = zoomLevel - 1; + interactionPoint.x >>= 1; + interactionPoint.y >>= 1; + origin.x >>= 1; + origin.y >>= 1; + } + } + + origin.x += g1->x_offset; + origin.y += g1->y_offset; + interactionPoint -= origin; + + if (interactionPoint.x < 0 || interactionPoint.y < 0 || interactionPoint.x >= g1->width + || interactionPoint.y >= g1->height) + { + return false; + } + + if (g1->flags & G1_FLAG_RLE_COMPRESSION) + { + return IsPixelPresentRLE(g1->offset, interactionPoint.x, interactionPoint.y); + } + + if (!(g1->flags & G1_FLAG_1)) + { + return IsPixelPresentBMP(imageType, g1, interactionPoint.x, interactionPoint.y, paletteMap); + } + + Guard::Assert(false, "Invalid image type encountered."); + return false; + } + + /** + * + * rct2: 0x00679023 + */ + + static bool IsSpriteInteractedWith(DrawPixelInfo& dpi, ImageId imageId, const ScreenCoordsXY& coords) + { + PROFILED_FUNCTION(); + + auto paletteMap = PaletteMap::GetDefault(); + uint8_t imageType; + if (imageId.HasPrimary() || imageId.IsRemap()) + { + imageType = IMAGE_TYPE_REMAP; + uint8_t paletteIndex; + if (imageId.HasSecondary()) + { + paletteIndex = imageId.GetPrimary(); + } + else + { + paletteIndex = imageId.GetRemap(); + } + if (auto pm = GetPaletteMapForColour(paletteIndex); pm.has_value()) + { + paletteMap = pm.value(); + } } else { - paletteIndex = imageId.GetRemap(); - } - if (auto pm = GetPaletteMapForColour(paletteIndex); pm.has_value()) - { - paletteMap = pm.value(); + imageType = IMAGE_TYPE_DEFAULT; } + return IsSpriteInteractedWithPaletteSet(dpi, imageId, coords, paletteMap, imageType); } - else + + /** + * + * rct2: 0x0068862C + */ + InteractionInfo SetInteractionInfoFromPaintSession(PaintSession* session, uint32_t viewFlags, uint16_t filter) { - imageType = IMAGE_TYPE_DEFAULT; - } - return IsSpriteInteractedWithPaletteSet(dpi, imageId, coords, paletteMap, imageType); -} + PROFILED_FUNCTION(); -/** - * - * rct2: 0x0068862C - */ -InteractionInfo SetInteractionInfoFromPaintSession(PaintSession* session, uint32_t viewFlags, uint16_t filter) -{ - PROFILED_FUNCTION(); + InteractionInfo info{}; - InteractionInfo info{}; - - PaintStruct* ps = session->PaintHead; - while (ps != nullptr) - { - PaintStruct* old_ps = ps; - PaintStruct* next_ps = ps; - while (next_ps != nullptr) + PaintStruct* ps = session->PaintHead; + while (ps != nullptr) { - ps = next_ps; - if (IsSpriteInteractedWith(session->DPI, ps->image_id, ps->ScreenPos)) + PaintStruct* old_ps = ps; + PaintStruct* next_ps = ps; + while (next_ps != nullptr) { - if (PSInteractionTypeIsInFilter(ps, filter) - && GetPaintStructVisibility(ps, viewFlags) == VisibilityKind::Visible) + ps = next_ps; + if (IsSpriteInteractedWith(session->DPI, ps->image_id, ps->ScreenPos)) { - info = { ps }; + if (PSInteractionTypeIsInFilter(ps, filter) + && GetPaintStructVisibility(ps, viewFlags) == VisibilityKind::Visible) + { + info = { ps }; + } } + next_ps = ps->Children; } - next_ps = ps->Children; - } #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wnull-dereference" - for (AttachedPaintStruct* attached_ps = ps->Attached; attached_ps != nullptr; attached_ps = attached_ps->NextEntry) - { - if (IsSpriteInteractedWith(session->DPI, attached_ps->image_id, ps->ScreenPos + attached_ps->RelativePos)) + for (AttachedPaintStruct* attached_ps = ps->Attached; attached_ps != nullptr; attached_ps = attached_ps->NextEntry) { - if (PSInteractionTypeIsInFilter(ps, filter) - && GetPaintStructVisibility(ps, viewFlags) == VisibilityKind::Visible) + if (IsSpriteInteractedWith(session->DPI, attached_ps->image_id, ps->ScreenPos + attached_ps->RelativePos)) { - info = { ps }; + if (PSInteractionTypeIsInFilter(ps, filter) + && GetPaintStructVisibility(ps, viewFlags) == VisibilityKind::Visible) + { + info = { ps }; + } } } - } #pragma GCC diagnostic pop - ps = old_ps->NextQuadrantEntry; - } - return info; -} - -/** - * - * rct2: 0x00685ADC - * screenX: eax - * screenY: ebx - * flags: edx - * x: ax - * y: cx - * interactionType: bl - * tileElement: edx - * viewport: edi - */ -InteractionInfo GetMapCoordinatesFromPos(const ScreenCoordsXY& screenCoords, int32_t flags) -{ - auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); - WindowBase* window = windowMgr->FindFromPoint(screenCoords); - return GetMapCoordinatesFromPosWindow(window, screenCoords, flags); -} - -InteractionInfo GetMapCoordinatesFromPosWindow(WindowBase* window, const ScreenCoordsXY& screenCoords, int32_t flags) -{ - InteractionInfo info{}; - if (window == nullptr || window->viewport == nullptr) - { + ps = old_ps->NextQuadrantEntry; + } return info; } - Viewport* viewport = window->viewport; - auto viewLoc = screenCoords; - viewLoc -= viewport->pos; - if (viewLoc.x >= 0 && viewLoc.x < static_cast(viewport->width) && viewLoc.y >= 0 - && viewLoc.y < static_cast(viewport->height)) + /** + * + * rct2: 0x00685ADC + * screenX: eax + * screenY: ebx + * flags: edx + * x: ax + * y: cx + * interactionType: bl + * tileElement: edx + * viewport: edi + */ + InteractionInfo GetMapCoordinatesFromPos(const ScreenCoordsXY& screenCoords, int32_t flags) { - viewLoc.x = viewport->zoom.ApplyTo(viewLoc.x); - viewLoc.y = viewport->zoom.ApplyTo(viewLoc.y); - viewLoc += viewport->viewPos; - if (viewport->zoom > ZoomLevel{ 0 }) - { - viewLoc.x &= viewport->zoom.ApplyTo(0xFFFFFFFF) & 0xFFFFFFFF; - viewLoc.y &= viewport->zoom.ApplyTo(0xFFFFFFFF) & 0xFFFFFFFF; - } - DrawPixelInfo dpi; - dpi.zoom_level = viewport->zoom; - dpi.x = viewport->zoom.ApplyInversedTo(viewLoc.x); - dpi.y = viewport->zoom.ApplyInversedTo(viewLoc.y); - dpi.height = 1; - dpi.width = 1; - - PaintSession* session = PaintSessionAlloc(dpi, viewport->flags, viewport->rotation); - PaintSessionGenerate(*session); - PaintSessionArrange(*session); - info = SetInteractionInfoFromPaintSession(session, viewport->flags, flags & 0xFFFF); - PaintSessionFree(session); + auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); + WindowBase* window = windowMgr->FindFromPoint(screenCoords); + return GetMapCoordinatesFromPosWindow(window, screenCoords, flags); } - return info; -} -/** - * screenRect represents 2D map coordinates at zoom 0. - */ -void ViewportInvalidate(const Viewport* viewport, const ScreenRect& screenRect) -{ - PROFILED_FUNCTION(); - - // if unknown viewport visibility, use the containing window to discover the status - if (viewport->visibility == VisibilityCache::Unknown) + InteractionInfo GetMapCoordinatesFromPosWindow(WindowBase* window, const ScreenCoordsXY& screenCoords, int32_t flags) { - auto windowManager = GetContext()->GetUiContext()->GetWindowManager(); - auto owner = windowManager->GetOwner(viewport); - if (owner != nullptr && owner->classification != WindowClass::MainWindow) + InteractionInfo info{}; + if (window == nullptr || window->viewport == nullptr) { - // note, window_is_visible will update viewport->visibility, so this should have a low hit count - if (!WindowIsVisible(*owner)) + return info; + } + + Viewport* viewport = window->viewport; + auto viewLoc = screenCoords; + viewLoc -= viewport->pos; + if (viewLoc.x >= 0 && viewLoc.x < static_cast(viewport->width) && viewLoc.y >= 0 + && viewLoc.y < static_cast(viewport->height)) + { + viewLoc.x = viewport->zoom.ApplyTo(viewLoc.x); + viewLoc.y = viewport->zoom.ApplyTo(viewLoc.y); + viewLoc += viewport->viewPos; + if (viewport->zoom > ZoomLevel{ 0 }) { - return; + viewLoc.x &= viewport->zoom.ApplyTo(0xFFFFFFFF) & 0xFFFFFFFF; + viewLoc.y &= viewport->zoom.ApplyTo(0xFFFFFFFF) & 0xFFFFFFFF; + } + DrawPixelInfo dpi; + dpi.zoom_level = viewport->zoom; + dpi.x = viewport->zoom.ApplyInversedTo(viewLoc.x); + dpi.y = viewport->zoom.ApplyInversedTo(viewLoc.y); + dpi.height = 1; + dpi.width = 1; + + PaintSession* session = PaintSessionAlloc(dpi, viewport->flags, viewport->rotation); + PaintSessionGenerate(*session); + PaintSessionArrange(*session); + info = SetInteractionInfoFromPaintSession(session, viewport->flags, flags & 0xFFFF); + PaintSessionFree(session); + } + return info; + } + + /** + * screenRect represents 2D map coordinates at zoom 0. + */ + void ViewportInvalidate(const Viewport* viewport, const ScreenRect& screenRect) + { + PROFILED_FUNCTION(); + + // if unknown viewport visibility, use the containing window to discover the status + if (viewport->visibility == VisibilityCache::Unknown) + { + auto windowManager = GetContext()->GetUiContext()->GetWindowManager(); + auto owner = windowManager->GetOwner(viewport); + if (owner != nullptr && owner->classification != WindowClass::MainWindow) + { + // note, window_is_visible will update viewport->visibility, so this should have a low hit count + if (!WindowIsVisible(*owner)) + { + return; + } } } + + if (viewport->visibility == VisibilityCache::Covered) + return; + + auto zoom = viewport->zoom; + auto viewPos = viewport->viewPos; + auto viewportScreenPos = viewport->pos; + + ScreenRect invalidRect = { { zoom.ApplyInversedTo(screenRect.GetLeft() - viewPos.x), + zoom.ApplyInversedTo(screenRect.GetTop() - viewPos.y) }, + { zoom.ApplyInversedTo(screenRect.GetRight() - viewPos.x), + zoom.ApplyInversedTo(screenRect.GetBottom() - viewPos.y) } }; + + if (invalidRect.GetTop() >= viewport->height || invalidRect.GetBottom() <= 0 || invalidRect.GetLeft() >= viewport->width + || invalidRect.GetRight() <= 0) + { + return; + } + invalidRect.Point1 += viewportScreenPos; + invalidRect.Point2 += viewportScreenPos; + GfxSetDirtyBlocks(invalidRect); } - if (viewport->visibility == VisibilityCache::Covered) - return; - - auto zoom = viewport->zoom; - auto viewPos = viewport->viewPos; - auto viewportScreenPos = viewport->pos; - - ScreenRect invalidRect = { - { zoom.ApplyInversedTo(screenRect.GetLeft() - viewPos.x), zoom.ApplyInversedTo(screenRect.GetTop() - viewPos.y) }, - { zoom.ApplyInversedTo(screenRect.GetRight() - viewPos.x), zoom.ApplyInversedTo(screenRect.GetBottom() - viewPos.y) } - }; - - if (invalidRect.GetTop() >= viewport->height || invalidRect.GetBottom() <= 0 || invalidRect.GetLeft() >= viewport->width - || invalidRect.GetRight() <= 0) + static Viewport* ViewportFindFromPoint(const ScreenCoordsXY& screenCoords) { - return; - } - invalidRect.Point1 += viewportScreenPos; - invalidRect.Point2 += viewportScreenPos; - GfxSetDirtyBlocks(invalidRect); -} + auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); + WindowBase* w = windowMgr->FindFromPoint(screenCoords); + if (w == nullptr) + return nullptr; -static Viewport* ViewportFindFromPoint(const ScreenCoordsXY& screenCoords) -{ - auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); - WindowBase* w = windowMgr->FindFromPoint(screenCoords); - if (w == nullptr) - return nullptr; - - Viewport* viewport = w->viewport; - if (viewport == nullptr) - return nullptr; - - if (viewport->ContainsScreen(screenCoords)) - return viewport; - - return nullptr; -} - -/** - * - * rct2: 0x00688972 - * In: - * screen_x: eax - * screen_y: ebx - * Out: - * x: ax - * y: bx - * tile_element: edx ? - * viewport: edi - */ -std::optional ScreenGetMapXY(const ScreenCoordsXY& screenCoords, Viewport** viewport) -{ - auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); - - // This will get the tile location but we will need the more accuracy - WindowBase* window = windowMgr->FindFromPoint(screenCoords); - if (window == nullptr || window->viewport == nullptr) - { - return std::nullopt; - } - auto myViewport = window->viewport; - auto info = GetMapCoordinatesFromPosWindow(window, screenCoords, EnumsToFlags(ViewportInteractionItem::Terrain)); - if (info.interactionType == ViewportInteractionItem::None) - { - return std::nullopt; - } - - auto start_vp_pos = myViewport->ScreenToViewportCoord(screenCoords); - CoordsXY cursorMapPos = info.Loc.ToTileCentre(); - - // Iterates the cursor location to work out exactly where on the tile it is - for (int32_t i = 0; i < 5; i++) - { - int32_t z = TileElementHeight(cursorMapPos); - cursorMapPos = ViewportPosToMapPos(start_vp_pos, z, myViewport->rotation); - cursorMapPos.x = std::clamp(cursorMapPos.x, info.Loc.x, info.Loc.x + 31); - cursorMapPos.y = std::clamp(cursorMapPos.y, info.Loc.y, info.Loc.y + 31); - } - - if (viewport != nullptr) - *viewport = myViewport; - - return cursorMapPos; -} - -/** - * - * rct2: 0x006894D4 - */ -std::optional ScreenGetMapXYWithZ(const ScreenCoordsXY& screenCoords, int32_t z) -{ - Viewport* viewport = ViewportFindFromPoint(screenCoords); - if (viewport == nullptr) - { - return std::nullopt; - } - - auto vpCoords = viewport->ScreenToViewportCoord(screenCoords); - auto mapPosition = ViewportPosToMapPos(vpCoords, z, viewport->rotation); - if (!MapIsLocationValid(mapPosition)) - { - return std::nullopt; - } - - return mapPosition; -} - -/** - * - * rct2: 0x00689604 - */ -std::optional ScreenGetMapXYQuadrant(const ScreenCoordsXY& screenCoords, uint8_t* quadrant) -{ - auto mapCoords = ScreenGetMapXY(screenCoords, nullptr); - if (!mapCoords.has_value()) - return std::nullopt; - - *quadrant = MapGetTileQuadrant(*mapCoords); - return mapCoords->ToTileStart(); -} - -/** - * - * rct2: 0x0068964B - */ -std::optional ScreenGetMapXYQuadrantWithZ(const ScreenCoordsXY& screenCoords, int32_t z, uint8_t* quadrant) -{ - auto mapCoords = ScreenGetMapXYWithZ(screenCoords, z); - if (!mapCoords.has_value()) - return std::nullopt; - - *quadrant = MapGetTileQuadrant(*mapCoords); - return mapCoords->ToTileStart(); -} - -/** - * - * rct2: 0x00689692 - */ -std::optional ScreenGetMapXYSide(const ScreenCoordsXY& screenCoords, uint8_t* side) -{ - auto mapCoords = ScreenGetMapXY(screenCoords, nullptr); - if (!mapCoords.has_value()) - return std::nullopt; - - *side = MapGetTileSide(*mapCoords); - return mapCoords->ToTileStart(); -} - -/** - * - * rct2: 0x006896DC - */ -std::optional ScreenGetMapXYSideWithZ(const ScreenCoordsXY& screenCoords, int32_t z, uint8_t* side) -{ - auto mapCoords = ScreenGetMapXYWithZ(screenCoords, z); - if (!mapCoords.has_value()) - return std::nullopt; - - *side = MapGetTileSide(*mapCoords); - return mapCoords->ToTileStart(); -} - -ScreenCoordsXY Translate3DTo2DWithZ(int32_t rotation, const CoordsXYZ& pos) -{ - auto rotated = pos.Rotate(rotation); - // Use right shift to avoid issues like #9301 - return ScreenCoordsXY{ rotated.y - rotated.x, ((rotated.x + rotated.y) >> 1) - pos.z }; -} - -/** - * Get current viewport rotation. - * - * If an invalid rotation is detected and DEBUG_LEVEL_1 is enabled, an error - * will be reported. - * - * @returns rotation in range 0-3 (inclusive) - */ -uint8_t GetCurrentRotation() -{ - auto* viewport = ViewportGetMain(); - if (viewport == nullptr) - { - LOG_VERBOSE("No viewport found! Will return 0."); - return 0; - } - uint8_t rotation = viewport->rotation; - uint8_t rotation_masked = rotation & 3; -#if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 - if (rotation != rotation_masked) - { - LOG_ERROR( - "Found wrong rotation %d! Will return %d instead.", static_cast(rotation), - static_cast(rotation_masked)); - } -#endif // DEBUG_LEVEL_1 - return rotation_masked; -} - -int32_t GetHeightMarkerOffset() -{ - // Height labels in units - if (Config::Get().general.ShowHeightAsUnits) - return 0; - - // Height labels in feet - if (Config::Get().general.MeasurementFormat == MeasurementFormat::Imperial) - return 1 * 256; - - // Height labels in metres - return 2 * 256; -} - -void ViewportSetSavedView() -{ - WindowBase* w = WindowGetMain(); - if (w != nullptr) - { Viewport* viewport = w->viewport; - auto& gameState = GetGameState(); + if (viewport == nullptr) + return nullptr; - gameState.SavedView = ScreenCoordsXY{ viewport->ViewWidth() / 2, viewport->ViewHeight() / 2 } + viewport->viewPos; + if (viewport->ContainsScreen(screenCoords)) + return viewport; - gameState.SavedViewZoom = viewport->zoom; - gameState.SavedViewRotation = viewport->rotation; + return nullptr; } -} + + /** + * + * rct2: 0x00688972 + * In: + * screen_x: eax + * screen_y: ebx + * Out: + * x: ax + * y: bx + * tile_element: edx ? + * viewport: edi + */ + std::optional ScreenGetMapXY(const ScreenCoordsXY& screenCoords, Viewport** viewport) + { + auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); + + // This will get the tile location but we will need the more accuracy + WindowBase* window = windowMgr->FindFromPoint(screenCoords); + if (window == nullptr || window->viewport == nullptr) + { + return std::nullopt; + } + auto myViewport = window->viewport; + auto info = GetMapCoordinatesFromPosWindow(window, screenCoords, EnumsToFlags(ViewportInteractionItem::Terrain)); + if (info.interactionType == ViewportInteractionItem::None) + { + return std::nullopt; + } + + auto start_vp_pos = myViewport->ScreenToViewportCoord(screenCoords); + CoordsXY cursorMapPos = info.Loc.ToTileCentre(); + + // Iterates the cursor location to work out exactly where on the tile it is + for (int32_t i = 0; i < 5; i++) + { + int32_t z = TileElementHeight(cursorMapPos); + cursorMapPos = ViewportPosToMapPos(start_vp_pos, z, myViewport->rotation); + cursorMapPos.x = std::clamp(cursorMapPos.x, info.Loc.x, info.Loc.x + 31); + cursorMapPos.y = std::clamp(cursorMapPos.y, info.Loc.y, info.Loc.y + 31); + } + + if (viewport != nullptr) + *viewport = myViewport; + + return cursorMapPos; + } + + /** + * + * rct2: 0x006894D4 + */ + std::optional ScreenGetMapXYWithZ(const ScreenCoordsXY& screenCoords, int32_t z) + { + Viewport* viewport = ViewportFindFromPoint(screenCoords); + if (viewport == nullptr) + { + return std::nullopt; + } + + auto vpCoords = viewport->ScreenToViewportCoord(screenCoords); + auto mapPosition = ViewportPosToMapPos(vpCoords, z, viewport->rotation); + if (!MapIsLocationValid(mapPosition)) + { + return std::nullopt; + } + + return mapPosition; + } + + /** + * + * rct2: 0x00689604 + */ + std::optional ScreenGetMapXYQuadrant(const ScreenCoordsXY& screenCoords, uint8_t* quadrant) + { + auto mapCoords = ScreenGetMapXY(screenCoords, nullptr); + if (!mapCoords.has_value()) + return std::nullopt; + + *quadrant = MapGetTileQuadrant(*mapCoords); + return mapCoords->ToTileStart(); + } + + /** + * + * rct2: 0x0068964B + */ + std::optional ScreenGetMapXYQuadrantWithZ(const ScreenCoordsXY& screenCoords, int32_t z, uint8_t* quadrant) + { + auto mapCoords = ScreenGetMapXYWithZ(screenCoords, z); + if (!mapCoords.has_value()) + return std::nullopt; + + *quadrant = MapGetTileQuadrant(*mapCoords); + return mapCoords->ToTileStart(); + } + + /** + * + * rct2: 0x00689692 + */ + std::optional ScreenGetMapXYSide(const ScreenCoordsXY& screenCoords, uint8_t* side) + { + auto mapCoords = ScreenGetMapXY(screenCoords, nullptr); + if (!mapCoords.has_value()) + return std::nullopt; + + *side = MapGetTileSide(*mapCoords); + return mapCoords->ToTileStart(); + } + + /** + * + * rct2: 0x006896DC + */ + std::optional ScreenGetMapXYSideWithZ(const ScreenCoordsXY& screenCoords, int32_t z, uint8_t* side) + { + auto mapCoords = ScreenGetMapXYWithZ(screenCoords, z); + if (!mapCoords.has_value()) + return std::nullopt; + + *side = MapGetTileSide(*mapCoords); + return mapCoords->ToTileStart(); + } + + ScreenCoordsXY Translate3DTo2DWithZ(int32_t rotation, const CoordsXYZ& pos) + { + auto rotated = pos.Rotate(rotation); + // Use right shift to avoid issues like #9301 + return ScreenCoordsXY{ rotated.y - rotated.x, ((rotated.x + rotated.y) >> 1) - pos.z }; + } + + /** + * Get current viewport rotation. + * + * If an invalid rotation is detected and DEBUG_LEVEL_1 is enabled, an error + * will be reported. + * + * @returns rotation in range 0-3 (inclusive) + */ + uint8_t GetCurrentRotation() + { + auto* viewport = ViewportGetMain(); + if (viewport == nullptr) + { + LOG_VERBOSE("No viewport found! Will return 0."); + return 0; + } + uint8_t rotation = viewport->rotation; + uint8_t rotation_masked = rotation & 3; +#if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 + if (rotation != rotation_masked) + { + LOG_ERROR( + "Found wrong rotation %d! Will return %d instead.", static_cast(rotation), + static_cast(rotation_masked)); + } +#endif // DEBUG_LEVEL_1 + return rotation_masked; + } + + int32_t GetHeightMarkerOffset() + { + // Height labels in units + if (Config::Get().general.ShowHeightAsUnits) + return 0; + + // Height labels in feet + if (Config::Get().general.MeasurementFormat == MeasurementFormat::Imperial) + return 1 * 256; + + // Height labels in metres + return 2 * 256; + } + + void ViewportSetSavedView() + { + WindowBase* w = WindowGetMain(); + if (w != nullptr) + { + Viewport* viewport = w->viewport; + auto& gameState = GetGameState(); + + gameState.SavedView = ScreenCoordsXY{ viewport->ViewWidth() / 2, viewport->ViewHeight() / 2 } + viewport->viewPos; + + gameState.SavedViewZoom = viewport->zoom; + gameState.SavedViewRotation = viewport->rotation; + } + } +} // namespace OpenRCT2 ZoomLevel ZoomLevel::min() { diff --git a/src/openrct2/interface/Viewport.h b/src/openrct2/interface/Viewport.h index 0d9c50c452..3b43670f68 100644 --- a/src/openrct2/interface/Viewport.h +++ b/src/openrct2/interface/Viewport.h @@ -20,54 +20,58 @@ struct PaintSession; struct PaintStruct; struct DrawPixelInfo; struct TileElement; -struct WindowBase; struct EntityBase; struct Guest; struct Staff; struct PaintEntry; -// Flags must currenly retain their values to avoid breaking plugins. -// Values can be changed when plugins move to using named constants. -enum : uint32_t +namespace OpenRCT2 { - VIEWPORT_FLAG_NONE = 0u, + struct WindowBase; - VIEWPORT_FLAG_GRIDLINES = (1u << 7), - VIEWPORT_FLAG_UNDERGROUND_INSIDE = (1u << 0), - VIEWPORT_FLAG_HIDE_BASE = (1u << 12), - VIEWPORT_FLAG_HIDE_VERTICAL = (1u << 13), + // Flags must currenly retain their values to avoid breaking plugins. + // Values can be changed when plugins move to using named constants. + enum : uint32_t + { + VIEWPORT_FLAG_NONE = 0u, - VIEWPORT_FLAG_SOUND_ON = (1u << 10), - VIEWPORT_FLAG_LAND_OWNERSHIP = (1u << 8), - VIEWPORT_FLAG_CONSTRUCTION_RIGHTS = (1u << 9), - VIEWPORT_FLAG_HIDE_ENTITIES = (1u << 14), - VIEWPORT_FLAG_CLIP_VIEW = (1u << 17), - VIEWPORT_FLAG_HIGHLIGHT_PATH_ISSUES = (1u << 18), - VIEWPORT_FLAG_TRANSPARENT_BACKGROUND = (1u << 19), + VIEWPORT_FLAG_GRIDLINES = (1u << 7), + VIEWPORT_FLAG_UNDERGROUND_INSIDE = (1u << 0), + VIEWPORT_FLAG_HIDE_BASE = (1u << 12), + VIEWPORT_FLAG_HIDE_VERTICAL = (1u << 13), - VIEWPORT_FLAG_LAND_HEIGHTS = (1u << 4), - VIEWPORT_FLAG_TRACK_HEIGHTS = (1u << 5), - VIEWPORT_FLAG_PATH_HEIGHTS = (1u << 6), + VIEWPORT_FLAG_SOUND_ON = (1u << 10), + VIEWPORT_FLAG_LAND_OWNERSHIP = (1u << 8), + VIEWPORT_FLAG_CONSTRUCTION_RIGHTS = (1u << 9), + VIEWPORT_FLAG_HIDE_ENTITIES = (1u << 14), + VIEWPORT_FLAG_CLIP_VIEW = (1u << 17), + VIEWPORT_FLAG_HIGHLIGHT_PATH_ISSUES = (1u << 18), + VIEWPORT_FLAG_TRANSPARENT_BACKGROUND = (1u << 19), - VIEWPORT_FLAG_HIDE_RIDES = (1u << 1), - VIEWPORT_FLAG_HIDE_VEHICLES = (1u << 20), - VIEWPORT_FLAG_HIDE_VEGETATION = (1u << 21), - VIEWPORT_FLAG_HIDE_SCENERY = (1u << 2), - VIEWPORT_FLAG_HIDE_PATHS = (1u << 16), - VIEWPORT_FLAG_HIDE_SUPPORTS = (1u << 3), - VIEWPORT_FLAG_HIDE_GUESTS = (1u << 11), - VIEWPORT_FLAG_HIDE_STAFF = (1u << 23), + VIEWPORT_FLAG_LAND_HEIGHTS = (1u << 4), + VIEWPORT_FLAG_TRACK_HEIGHTS = (1u << 5), + VIEWPORT_FLAG_PATH_HEIGHTS = (1u << 6), - VIEWPORT_FLAG_INVISIBLE_RIDES = (1u << 24), - VIEWPORT_FLAG_INVISIBLE_VEHICLES = (1u << 25), - VIEWPORT_FLAG_INVISIBLE_VEGETATION = (1u << 26), - VIEWPORT_FLAG_INVISIBLE_SCENERY = (1u << 27), - VIEWPORT_FLAG_INVISIBLE_PATHS = (1u << 28), - VIEWPORT_FLAG_INVISIBLE_SUPPORTS = (1u << 29), + VIEWPORT_FLAG_HIDE_RIDES = (1u << 1), + VIEWPORT_FLAG_HIDE_VEHICLES = (1u << 20), + VIEWPORT_FLAG_HIDE_VEGETATION = (1u << 21), + VIEWPORT_FLAG_HIDE_SCENERY = (1u << 2), + VIEWPORT_FLAG_HIDE_PATHS = (1u << 16), + VIEWPORT_FLAG_HIDE_SUPPORTS = (1u << 3), + VIEWPORT_FLAG_HIDE_GUESTS = (1u << 11), + VIEWPORT_FLAG_HIDE_STAFF = (1u << 23), - VIEWPORT_FLAG_INDEPEDENT_ROTATION = (1u << 30), - VIEWPORT_FLAG_RENDERING_INHIBITED = (1u << 31), -}; + VIEWPORT_FLAG_INVISIBLE_RIDES = (1u << 24), + VIEWPORT_FLAG_INVISIBLE_VEHICLES = (1u << 25), + VIEWPORT_FLAG_INVISIBLE_VEGETATION = (1u << 26), + VIEWPORT_FLAG_INVISIBLE_SCENERY = (1u << 27), + VIEWPORT_FLAG_INVISIBLE_PATHS = (1u << 28), + VIEWPORT_FLAG_INVISIBLE_SUPPORTS = (1u << 29), + + VIEWPORT_FLAG_INDEPEDENT_ROTATION = (1u << 30), + VIEWPORT_FLAG_RENDERING_INHIBITED = (1u << 31), + }; +} // namespace OpenRCT2 enum class VisibilityKind { @@ -103,75 +107,78 @@ enum class ViewportVisibility : uint8_t UndergroundViewGhostOff = 5, }; -constexpr uint16_t ViewportInteractionItemAll = std::numeric_limits::max(); - -struct InteractionInfo +namespace OpenRCT2 { - InteractionInfo() = default; - InteractionInfo(const PaintStruct* ps); - CoordsXY Loc; - TileElement* Element{}; - EntityBase* Entity{}; - ViewportInteractionItem interactionType = ViewportInteractionItem::None; -}; + constexpr uint16_t ViewportInteractionItemAll = std::numeric_limits::max(); -constexpr int32_t kMaxViewportCount = kWindowLimitMax; + struct InteractionInfo + { + InteractionInfo() = default; + InteractionInfo(const PaintStruct* ps); + CoordsXY Loc; + TileElement* Element{}; + EntityBase* Entity{}; + ViewportInteractionItem interactionType = ViewportInteractionItem::None; + }; -/** - * A reference counter for whether something is forcing the grid lines to show. When the counter - * is decremented to 0, the grid lines are hidden. - */ -extern uint8_t gShowGridLinesRefCount; -extern uint8_t gShowLandRightsRefCount; -extern uint8_t gShowConstructionRightsRefCount; + constexpr int32_t kMaxViewportCount = kWindowLimitMax; -// rct2: 0x014234BC -extern Viewport* g_music_tracking_viewport; + /** + * A reference counter for whether something is forcing the grid lines to show. When the counter + * is decremented to 0, the grid lines are hidden. + */ + extern uint8_t gShowGridLinesRefCount; + extern uint8_t gShowLandRightsRefCount; + extern uint8_t gShowConstructionRightsRefCount; -void ViewportInitAll(); -std::optional centre_2d_coordinates(const CoordsXYZ& loc, Viewport* viewport); -void ViewportCreate(WindowBase* w, const ScreenCoordsXY& screenCoords, int32_t width, int32_t height, const Focus& focus); -void ViewportRemove(Viewport* viewport); + // rct2: 0x014234BC + extern Viewport* g_music_tracking_viewport; -void ViewportsInvalidate(int32_t x, int32_t y, int32_t z0, int32_t z1, ZoomLevel maxZoom); -void ViewportsInvalidate(const CoordsXYZ& pos, int32_t width, int32_t minHeight, int32_t maxHeight, ZoomLevel maxZoom); -void ViewportsInvalidate(const ScreenRect& screenRect, ZoomLevel maxZoom = ZoomLevel{ -1 }); -void ViewportUpdatePosition(WindowBase* window); -void ViewportUpdateSmartFollowGuest(WindowBase* window, const Guest& peep); -void ViewportRotateSingle(WindowBase* window, int32_t direction); -void ViewportRotateAll(int32_t direction); -void ViewportRender(DrawPixelInfo& dpi, const Viewport* viewport); + void ViewportInitAll(); + std::optional centre_2d_coordinates(const CoordsXYZ& loc, Viewport* viewport); + void ViewportCreate(WindowBase* w, const ScreenCoordsXY& screenCoords, int32_t width, int32_t height, const Focus& focus); + void ViewportRemove(Viewport* viewport); -CoordsXYZ ViewportAdjustForMapHeight(const ScreenCoordsXY& startCoords, uint8_t rotation); + void ViewportsInvalidate(int32_t x, int32_t y, int32_t z0, int32_t z1, ZoomLevel maxZoom); + void ViewportsInvalidate(const CoordsXYZ& pos, int32_t width, int32_t minHeight, int32_t maxHeight, ZoomLevel maxZoom); + void ViewportsInvalidate(const ScreenRect& screenRect, ZoomLevel maxZoom = ZoomLevel{ -1 }); + void ViewportUpdatePosition(WindowBase* window); + void ViewportUpdateSmartFollowGuest(WindowBase* window, const Guest& peep); + void ViewportRotateSingle(WindowBase* window, int32_t direction); + void ViewportRotateAll(int32_t direction); + void ViewportRender(DrawPixelInfo& dpi, const Viewport* viewport); -CoordsXY ViewportPosToMapPos(const ScreenCoordsXY& coords, int32_t z, uint8_t rotation); -std::optional ScreenPosToMapPos(const ScreenCoordsXY& screenCoords, int32_t* direction); + CoordsXYZ ViewportAdjustForMapHeight(const ScreenCoordsXY& startCoords, uint8_t rotation); -void ShowGridlines(); -void HideGridlines(); -void ShowLandRights(); -void HideLandRights(); -void ShowConstructionRights(); -void HideConstructionRights(); -void ViewportSetVisibility(ViewportVisibility mode); + CoordsXY ViewportPosToMapPos(const ScreenCoordsXY& coords, int32_t z, uint8_t rotation); + std::optional ScreenPosToMapPos(const ScreenCoordsXY& screenCoords, int32_t* direction); -InteractionInfo GetMapCoordinatesFromPos(const ScreenCoordsXY& screenCoords, int32_t flags); -InteractionInfo GetMapCoordinatesFromPosWindow(WindowBase* window, const ScreenCoordsXY& screenCoords, int32_t flags); + void ShowGridlines(); + void HideGridlines(); + void ShowLandRights(); + void HideLandRights(); + void ShowConstructionRights(); + void HideConstructionRights(); + void ViewportSetVisibility(ViewportVisibility mode); -InteractionInfo SetInteractionInfoFromPaintSession(PaintSession* session, uint32_t viewFlags, uint16_t filter); + InteractionInfo GetMapCoordinatesFromPos(const ScreenCoordsXY& screenCoords, int32_t flags); + InteractionInfo GetMapCoordinatesFromPosWindow(WindowBase* window, const ScreenCoordsXY& screenCoords, int32_t flags); -std::optional ScreenGetMapXY(const ScreenCoordsXY& screenCoords, Viewport** viewport); -std::optional ScreenGetMapXYWithZ(const ScreenCoordsXY& screenCoords, int32_t z); -std::optional ScreenGetMapXYQuadrant(const ScreenCoordsXY& screenCoords, uint8_t* quadrant); -std::optional ScreenGetMapXYQuadrantWithZ(const ScreenCoordsXY& screenCoords, int32_t z, uint8_t* quadrant); -std::optional ScreenGetMapXYSide(const ScreenCoordsXY& screenCoords, uint8_t* side); -std::optional ScreenGetMapXYSideWithZ(const ScreenCoordsXY& screenCoords, int32_t z, uint8_t* side); + InteractionInfo SetInteractionInfoFromPaintSession(PaintSession* session, uint32_t viewFlags, uint16_t filter); -ScreenCoordsXY Translate3DTo2DWithZ(int32_t rotation, const CoordsXYZ& pos); + std::optional ScreenGetMapXY(const ScreenCoordsXY& screenCoords, Viewport** viewport); + std::optional ScreenGetMapXYWithZ(const ScreenCoordsXY& screenCoords, int32_t z); + std::optional ScreenGetMapXYQuadrant(const ScreenCoordsXY& screenCoords, uint8_t* quadrant); + std::optional ScreenGetMapXYQuadrantWithZ(const ScreenCoordsXY& screenCoords, int32_t z, uint8_t* quadrant); + std::optional ScreenGetMapXYSide(const ScreenCoordsXY& screenCoords, uint8_t* side); + std::optional ScreenGetMapXYSideWithZ(const ScreenCoordsXY& screenCoords, int32_t z, uint8_t* side); -uint8_t GetCurrentRotation(); -int32_t GetHeightMarkerOffset(); + ScreenCoordsXY Translate3DTo2DWithZ(int32_t rotation, const CoordsXYZ& pos); -void ViewportSetSavedView(); + uint8_t GetCurrentRotation(); + int32_t GetHeightMarkerOffset(); -VisibilityKind GetPaintStructVisibility(const PaintStruct* ps, uint32_t viewFlags); + void ViewportSetSavedView(); + + VisibilityKind GetPaintStructVisibility(const PaintStruct* ps, uint32_t viewFlags); +} // namespace OpenRCT2 diff --git a/src/openrct2/interface/Widget.h b/src/openrct2/interface/Widget.h index d4d5b2b106..e89826f95a 100644 --- a/src/openrct2/interface/Widget.h +++ b/src/openrct2/interface/Widget.h @@ -9,56 +9,156 @@ #pragma once +#include "../core/StringTypes.h" +#include "../drawing/ImageId.hpp" +#include "../localisation/StringIdType.h" +#include "../world/Location.hpp" + #include -struct WindowBase; - -using WidgetIndex = int16_t; - -enum class WindowWidgetType : uint8_t +namespace OpenRCT2 { - Empty = 0, - Frame = 1, - Resize = 2, - ImgBtn = 3, - ColourBtn = 6, - TrnBtn = 7, - Tab = 8, - FlatBtn = 9, - Button = 10, - LabelCentred = 12, // Centred text - TableHeader = 13, // Left-aligned textual button - Label = 14, // Left-aligned text - Spinner = 15, - DropdownMenu = 16, - Viewport = 17, - Groupbox = 19, - Caption = 20, - CloseBox = 21, - Scroll = 22, - Checkbox = 23, - Placeholder = 25, - ProgressBar = 29, - Custom = 28, - TextBox = 27, - Last = 26, -}; + using WidgetIndex = uint16_t; + constexpr WidgetIndex kWidgetIndexNull = 0xFFFF; -constexpr uint8_t kCloseButtonWidth = 10; + enum class WindowWidgetType : uint8_t + { + Empty = 0, + Frame = 1, + Resize = 2, + ImgBtn = 3, + ColourBtn = 6, + TrnBtn = 7, + Tab = 8, + FlatBtn = 9, + Button = 10, + LabelCentred = 12, // Centred text + TableHeader = 13, // Left-aligned textual button + Label = 14, // Left-aligned text + Spinner = 15, + DropdownMenu = 16, + Viewport = 17, + Groupbox = 19, + Caption = 20, + CloseBox = 21, + Scroll = 22, + Checkbox = 23, + Placeholder = 25, + ProgressBar = 29, + Custom = 28, + TextBox = 27, + }; -constexpr int32_t kScrollableRowHeight = 12; -constexpr uint8_t kListRowHeight = 12; -constexpr uint8_t kTableCellHeight = 12; -constexpr uint8_t kButtonFaceHeight = 12; -constexpr uint8_t kSpinnerHeight = 12; -constexpr uint8_t kDropdownHeight = 12; + using WidgetFlags = uint32_t; + namespace WIDGET_FLAGS + { + const WidgetFlags TEXT_IS_STRING = 1 << 0; + const WidgetFlags IS_PRESSED = 1 << 2; + const WidgetFlags IS_DISABLED = 1 << 3; + const WidgetFlags TOOLTIP_IS_STRING = 1 << 4; + const WidgetFlags IS_HIDDEN = 1 << 5; + const WidgetFlags IS_HOLDABLE = 1 << 6; + } // namespace WIDGET_FLAGS -constexpr uint16_t kTextInputSize = 1024; -constexpr uint16_t kTopToolbarHeight = 27; + enum + { + SCROLL_HORIZONTAL = (1 << 0), + SCROLL_VERTICAL = (1 << 1), + SCROLL_BOTH = SCROLL_HORIZONTAL | SCROLL_VERTICAL + }; -enum -{ - SCROLL_HORIZONTAL = (1 << 0), - SCROLL_VERTICAL = (1 << 1), - SCROLL_BOTH = SCROLL_HORIZONTAL | SCROLL_VERTICAL -}; + struct Widget + { + WindowWidgetType type{}; + uint8_t colour{}; + int16_t left{}; + int16_t right{}; + int16_t top{}; + int16_t bottom{}; + union + { + uint32_t content; + ImageId image{}; + StringId text; + utf8* string; + }; + StringId tooltip{ STR_NONE }; + + // New properties + WidgetFlags flags{}; + utf8* sztooltip{}; + + int16_t width() const + { + return right - left; + } + + int16_t height() const + { + return bottom - top; + } + + int16_t midX() const + { + return (left + right) / 2; + } + + int16_t midY() const + { + return (top + bottom) / 2; + } + + int16_t textTop() const + { + if (height() >= 10) + return std::max(top, top + (height() / 2) - 5); + + return top - 1; + } + + void moveRight(int32_t amount) + { + left += amount; + right += amount; + } + + void moveDown(int32_t amount) + { + top += amount; + bottom += amount; + } + + void moveTo(ScreenCoordsXY coords) + { + moveRight(coords.x - left); + moveDown(coords.y - top); + } + + void moveToX(int16_t x) + { + moveRight(x - left); + } + + void moveToY(int16_t y) + { + moveDown(y - top); + } + + bool IsVisible() const + { + return !(flags & OpenRCT2::WIDGET_FLAGS::IS_HIDDEN); + } + }; + + constexpr uint8_t kCloseButtonWidth = 10; + + constexpr int32_t kScrollableRowHeight = 12; + constexpr uint8_t kListRowHeight = 12; + constexpr uint8_t kTableCellHeight = 12; + constexpr uint8_t kButtonFaceHeight = 12; + constexpr uint8_t kSpinnerHeight = 12; + constexpr uint8_t kDropdownHeight = 12; + + constexpr uint16_t kTextInputSize = 1024; + constexpr uint16_t kTopToolbarHeight = 27; +} // namespace OpenRCT2 diff --git a/src/openrct2/interface/Window.cpp b/src/openrct2/interface/Window.cpp index ffc5fc09a2..82e1285862 100644 --- a/src/openrct2/interface/Window.cpp +++ b/src/openrct2/interface/Window.cpp @@ -39,22 +39,23 @@ #include #include -using namespace OpenRCT2; +namespace OpenRCT2 +{ -std::list> g_window_list; -WindowBase* gWindowAudioExclusive; + std::list> g_window_list; + WindowBase* gWindowAudioExclusive; -WindowCloseModifier gLastCloseModifier = { { WindowClass::Null, 0 }, CloseWindowModifier::None }; + WindowCloseModifier gLastCloseModifier = { { WindowClass::Null, 0 }, CloseWindowModifier::None }; -uint32_t gWindowUpdateTicks; -colour_t gCurrentWindowColours[3]; + uint32_t gWindowUpdateTicks; + colour_t gCurrentWindowColours[3]; -Tool gCurrentToolId; -WidgetRef gCurrentToolWidget; + Tool gCurrentToolId; + WidgetRef gCurrentToolWidget; -// converted from uint16_t values at 0x009A41EC - 0x009A4230 -// these are percentage coordinates of the viewport to centre to, if a window is obscuring a location, the next is tried -// clang-format off + // converted from uint16_t values at 0x009A41EC - 0x009A4230 + // these are percentage coordinates of the viewport to centre to, if a window is obscuring a location, the next is tried + // clang-format off static constexpr float window_scroll_locations[][2] = { { 0.5f, 0.5f }, { 0.75f, 0.5f }, @@ -74,1261 +75,1267 @@ static constexpr float window_scroll_locations[][2] = { { 0.125f, 0.875f }, { 0.125f, 0.125f }, }; -// clang-format on + // clang-format on -namespace OpenRCT2::WindowCloseFlags -{ - static constexpr uint32_t None = 0; - static constexpr uint32_t CloseSingle = (1 << 0); -} // namespace OpenRCT2::WindowCloseFlags - -static void WindowDrawCore(DrawPixelInfo& dpi, WindowBase& w, int32_t left, int32_t top, int32_t right, int32_t bottom); -static void WindowDrawSingle(DrawPixelInfo& dpi, WindowBase& w, int32_t left, int32_t top, int32_t right, int32_t bottom); - -std::list>::iterator WindowGetIterator(const WindowBase* w) -{ - return std::find_if(g_window_list.begin(), g_window_list.end(), [w](const std::shared_ptr& w2) -> bool { - return w == w2.get(); - }); -} - -void WindowVisitEach(std::function func) -{ - for (auto& w : g_window_list) + namespace WindowCloseFlags { - if (w->flags & WF_DEAD) - continue; - func(w.get()); - } -} + static constexpr uint32_t None = 0; + static constexpr uint32_t CloseSingle = (1 << 0); + } // namespace WindowCloseFlags -void WindowSetFlagForAllViewports(uint32_t viewportFlag, bool enabled) -{ - WindowVisitEach([&](WindowBase* w) { - if (w->viewport != nullptr) - { - if (enabled) - w->viewport->flags |= viewportFlag; - else - w->viewport->flags &= ~viewportFlag; - } - }); -} + static void WindowDrawCore(DrawPixelInfo& dpi, WindowBase& w, int32_t left, int32_t top, int32_t right, int32_t bottom); + static void WindowDrawSingle(DrawPixelInfo& dpi, WindowBase& w, int32_t left, int32_t top, int32_t right, int32_t bottom); -/** - * - * rct2: 0x006ED7B0 - */ -void WindowDispatchUpdateAll() -{ - // gTooltipNotShownTicks++; - WindowVisitEach([&](WindowBase* w) { w->OnUpdate(); }); -} - -void WindowUpdateAllViewports() -{ - WindowVisitEach([&](WindowBase* w) { - if (w->viewport != nullptr && WindowIsVisible(*w)) - { - ViewportUpdatePosition(w); - } - }); -} - -/** - * - * rct2: 0x006E77A1 - */ -void WindowUpdateAll() -{ - // Remove all windows in g_window_list that have the WF_DEAD flag - g_window_list.remove_if([](auto&& w) -> bool { return w->flags & WF_DEAD; }); - - // Periodic update happens every second so 40 ticks. - if (gCurrentRealTimeTicks >= gWindowUpdateTicks) + std::list>::iterator WindowGetIterator(const WindowBase* w) { - gWindowUpdateTicks = gCurrentRealTimeTicks + kGameUpdateFPS; - - WindowVisitEach([](WindowBase* w) { w->OnPeriodicUpdate(); }); + return std::find_if(g_window_list.begin(), g_window_list.end(), [w](const std::shared_ptr& w2) -> bool { + return w == w2.get(); + }); } - // Border flash invalidation - WindowVisitEach([](WindowBase* w) { - if (w->flags & WF_WHITE_BORDER_MASK) - { - w->flags -= WF_WHITE_BORDER_ONE; - if (!(w->flags & WF_WHITE_BORDER_MASK)) - { - w->Invalidate(); - } - } - }); - - auto windowManager = GetContext()->GetUiContext()->GetWindowManager(); - windowManager->UpdateMouseWheel(); -} - -void WindowNotifyLanguageChange() -{ - WindowVisitEach([&](WindowBase* w) { w->OnLanguageChange(); }); -} - -static void WindowCloseSurplus(int32_t cap, WindowClass avoid_classification) -{ - // find the amount of windows that are currently open - auto count = static_cast(g_window_list.size()); - // difference between amount open and cap = amount to close - auto diff = count - kWindowLimitReserved - cap; - for (auto i = 0; i < diff; i++) + void WindowVisitEach(std::function func) { - // iterates through the list until it finds the newest window, or a window that can be closed - WindowBase* foundW{}; for (auto& w : g_window_list) { if (w->flags & WF_DEAD) continue; - if (!(w->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT | WF_NO_AUTO_CLOSE))) + func(w.get()); + } + } + + void WindowSetFlagForAllViewports(uint32_t viewportFlag, bool enabled) + { + WindowVisitEach([&](WindowBase* w) { + if (w->viewport != nullptr) { - foundW = w.get(); - break; + if (enabled) + w->viewport->flags |= viewportFlag; + else + w->viewport->flags &= ~viewportFlag; } - } - // skip window if window matches specified WindowClass (as user may be modifying via options) - if (avoid_classification != WindowClass::Null && foundW != nullptr && foundW->classification == avoid_classification) - { - continue; - } - WindowClose(*foundW); + }); } -} -/* - * Changes the maximum amount of windows allowed - */ -void WindowSetWindowLimit(int32_t value) -{ - int32_t prev = Config::Get().general.WindowLimit; - int32_t val = std::clamp(value, kWindowLimitMin, kWindowLimitMax); - Config::Get().general.WindowLimit = val; - Config::Save(); - // Checks if value decreases and then closes surplus - // windows if one sets a limit lower than the number of windows open - if (val < prev) + /** + * + * rct2: 0x006ED7B0 + */ + void WindowDispatchUpdateAll() { - WindowCloseSurplus(val, WindowClass::Options); + // gTooltipNotShownTicks++; + WindowVisitEach([&](WindowBase* w) { w->OnUpdate(); }); } -} -/** - * Closes the specified window. - * rct2: 0x006ECD4C - * - * @param window The window to close (esi). - */ -void WindowClose(WindowBase& w) -{ - w.OnClose(); - - // Remove viewport - w.RemoveViewport(); - - // Invalidate the window (area) - w.Invalidate(); - - w.flags |= WF_DEAD; -} - -template -static void WindowCloseByCondition(TPred pred, uint32_t flags = WindowCloseFlags::None) -{ - for (auto it = g_window_list.rbegin(); it != g_window_list.rend(); ++it) + void WindowUpdateAllViewports() { - auto& wnd = *(*it); - if (wnd.flags & WF_DEAD) - continue; - - if (pred(&wnd)) - { - WindowClose(wnd); - if (flags & WindowCloseFlags::CloseSingle) + WindowVisitEach([&](WindowBase* w) { + if (w->viewport != nullptr && WindowIsVisible(*w)) { - return; + ViewportUpdatePosition(w); } - } - } -} - -/** - * Closes all windows with the specified window class. - * rct2: 0x006ECCF4 - * @param cls (cl) with bit 15 set - */ -void WindowCloseByClass(WindowClass cls) -{ - WindowCloseByCondition([&](WindowBase* w) -> bool { return w->classification == cls; }); -} - -/** - * Closes all windows with specified window class and number. - * rct2: 0x006ECCF4 - * @param cls (cl) without bit 15 set - * @param number (dx) - */ -void WindowCloseByNumber(WindowClass cls, rct_windownumber number) -{ - WindowCloseByCondition([cls, number](WindowBase* w) -> bool { return w->classification == cls && w->number == number; }); -} - -// TODO: Refactor this to use variant once the new window class is done. -void WindowCloseByNumber(WindowClass cls, EntityId number) -{ - WindowCloseByNumber(cls, static_cast(number.ToUnderlying())); -} - -/** - * Closes the top-most window - * - * rct2: 0x006E403C - */ -void WindowCloseTop() -{ - WindowCloseByClass(WindowClass::Dropdown); - - if (gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) - { - if (GetGameState().EditorStep != EditorStep::LandscapeEditor) - return; + }); } - auto pred = [](WindowBase* w) -> bool { return !(w->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT)); }; - WindowCloseByCondition(pred, WindowCloseFlags::CloseSingle); -} - -/** - * Closes all open windows - * - * rct2: 0x006EE927 - */ -void WindowCloseAll() -{ - WindowCloseByClass(WindowClass::Dropdown); - WindowCloseByCondition([](WindowBase* w) -> bool { return !(w->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT)); }); -} - -void WindowCloseAllExceptClass(WindowClass cls) -{ - WindowCloseByClass(WindowClass::Dropdown); - WindowCloseByCondition([cls](WindowBase* w) -> bool { - return w->classification != cls && !(w->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT)); - }); -} - -/** - * Closes all windows, save for those having any of the passed flags. - */ -void WindowCloseAllExceptFlags(uint16_t flags) -{ - WindowCloseByCondition([flags](WindowBase* w) -> bool { return !(w->flags & flags); }); -} - -/** - * Closes all windows except the specified window number and class. - * @param number (dx) - * @param cls (cl) without bit 15 set - */ -void WindowCloseAllExceptNumberAndClass(rct_windownumber number, WindowClass cls) -{ - WindowCloseByClass(WindowClass::Dropdown); - WindowCloseByCondition([cls, number](WindowBase* w) -> bool { - return (!(w->number == number && w->classification == cls) && !(w->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT))); - }); -} - -/** - * Invalidates the specified window. - * rct2: 0x006EB13A - * - * @param window The window to invalidate (esi). - */ -template -static void WindowInvalidateByCondition(TPred pred) -{ - WindowVisitEach([pred](WindowBase* w) { - if (pred(w)) - { - w->Invalidate(); - } - }); -} - -/** - * Invalidates all windows with the specified window class. - * rct2: 0x006EC3AC - * @param cls (al) with bit 14 set - */ -void WindowInvalidateByClass(WindowClass cls) -{ - WindowInvalidateByCondition([cls](WindowBase* w) -> bool { return w->classification == cls; }); -} - -/** - * Invalidates all windows with the specified window class and number. - * rct2: 0x006EC3AC - */ -void WindowInvalidateByNumber(WindowClass cls, rct_windownumber number) -{ - WindowInvalidateByCondition( - [cls, number](WindowBase* w) -> bool { return w->classification == cls && w->number == number; }); -} - -// TODO: Use variant for this once the window framework is done. -void WindowInvalidateByNumber(WindowClass cls, EntityId id) -{ - WindowInvalidateByNumber(cls, static_cast(id.ToUnderlying())); -} - -/** - * Invalidates all windows. - */ -void WindowInvalidateAll() -{ - WindowVisitEach([](WindowBase* w) { w->Invalidate(); }); -} - -/** - * Invalidates the specified widget of a window. - * rct2: 0x006EC402 - */ -void WidgetInvalidate(WindowBase& w, WidgetIndex widgetIndex) -{ -#ifdef DEBUG - for (int32_t i = 0; i <= widgetIndex; i++) + /** + * + * rct2: 0x006E77A1 + */ + void WindowUpdateAll() { - assert(w.widgets[i].type != WindowWidgetType::Last); - } -#endif + // Remove all windows in g_window_list that have the WF_DEAD flag + g_window_list.remove_if([](auto&& w) -> bool { return w->flags & WF_DEAD; }); - const auto& widget = w.widgets[widgetIndex]; - if (widget.left == -2) - return; - - GfxSetDirtyBlocks({ { w.windowPos + ScreenCoordsXY{ widget.left, widget.top } }, - { w.windowPos + ScreenCoordsXY{ widget.right + 1, widget.bottom + 1 } } }); -} - -template -static void widget_invalidate_by_condition(TPred pred) -{ - WindowVisitEach([pred](WindowBase* w) { - if (pred(w)) + // Periodic update happens every second so 40 ticks. + if (gCurrentRealTimeTicks >= gWindowUpdateTicks) { - w->Invalidate(); + gWindowUpdateTicks = gCurrentRealTimeTicks + kGameUpdateFPS; + + WindowVisitEach([](WindowBase* w) { w->OnPeriodicUpdate(); }); } - }); -} -/** - * Invalidates the specified widget of all windows that match the specified window class. - */ -void WidgetInvalidateByClass(WindowClass cls, WidgetIndex widgetIndex) -{ - WindowVisitEach([cls, widgetIndex](WindowBase* w) { - if (w->classification == cls) - { - WidgetInvalidate(*w, widgetIndex); - } - }); -} - -/** - * Invalidates the specified widget of all windows that match the specified window class and number. - * rct2: 0x006EC3AC - */ -void WidgetInvalidateByNumber(WindowClass cls, rct_windownumber number, WidgetIndex widgetIndex) -{ - WindowVisitEach([cls, number, widgetIndex](WindowBase* w) { - if (w->classification == cls && w->number == number) - { - WidgetInvalidate(*w, widgetIndex); - } - }); -} - -int32_t WindowGetScrollDataIndex(const WindowBase& w, WidgetIndex widget_index) -{ - int32_t i, result; - - result = 0; - for (i = 0; i < widget_index; i++) - { - const auto& widget = w.widgets[i]; - if (widget.type == WindowWidgetType::Scroll) - result++; - } - return result; -} - -/** - * - * rct2: 0x006ECDA4 - */ -WindowBase* WindowBringToFront(WindowBase& w) -{ - if (!(w.flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT))) - { - auto itSourcePos = WindowGetIterator(&w); - if (itSourcePos != g_window_list.end()) - { - // Insert in front of the first non-stick-to-front window - auto itDestPos = g_window_list.begin(); - for (auto it = g_window_list.rbegin(); it != g_window_list.rend(); it++) + // Border flash invalidation + WindowVisitEach([](WindowBase* w) { + if (w->flags & WF_WHITE_BORDER_MASK) { - auto& w2 = *it; - if (!(w2->flags & WF_STICK_TO_FRONT)) + w->flags -= WF_WHITE_BORDER_ONE; + if (!(w->flags & WF_WHITE_BORDER_MASK)) { - itDestPos = it.base(); + w->Invalidate(); + } + } + }); + + auto windowManager = GetContext()->GetUiContext()->GetWindowManager(); + windowManager->UpdateMouseWheel(); + } + + void WindowNotifyLanguageChange() + { + WindowVisitEach([&](WindowBase* w) { w->OnLanguageChange(); }); + } + + static void WindowCloseSurplus(int32_t cap, WindowClass avoid_classification) + { + // find the amount of windows that are currently open + auto count = static_cast(g_window_list.size()); + // difference between amount open and cap = amount to close + auto diff = count - kWindowLimitReserved - cap; + for (auto i = 0; i < diff; i++) + { + // iterates through the list until it finds the newest window, or a window that can be closed + WindowBase* foundW{}; + for (auto& w : g_window_list) + { + if (w->flags & WF_DEAD) + continue; + if (!(w->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT | WF_NO_AUTO_CLOSE))) + { + foundW = w.get(); break; } } - - g_window_list.splice(itDestPos, g_window_list, itSourcePos); - w.Invalidate(); - - if (w.windowPos.x + w.width < 20) + // skip window if window matches specified WindowClass (as user may be modifying via options) + if (avoid_classification != WindowClass::Null && foundW != nullptr + && foundW->classification == avoid_classification) { - int32_t i = 20 - w.windowPos.x; - w.windowPos.x += i; - if (w.viewport != nullptr) - w.viewport->pos.x += i; - w.Invalidate(); + continue; } + WindowClose(*foundW); } } - return &w; -} -WindowBase* WindowBringToFrontByClassWithFlags(WindowClass cls, uint16_t flags) -{ - auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); - WindowBase* w = windowMgr->FindByClass(cls); - if (w != nullptr) + /* + * Changes the maximum amount of windows allowed + */ + void WindowSetWindowLimit(int32_t value) { - w->flags |= flags; - w->Invalidate(); - w = WindowBringToFront(*w); - } - - return w; -} - -WindowBase* WindowBringToFrontByClass(WindowClass cls) -{ - return WindowBringToFrontByClassWithFlags(cls, WF_WHITE_BORDER_MASK); -} - -/** - * - * rct2: 0x006ED78A - * cls (cl) - * number (dx) - */ -WindowBase* WindowBringToFrontByNumber(WindowClass cls, rct_windownumber number) -{ - auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); - WindowBase* w = windowMgr->FindByNumber(cls, number); - if (w != nullptr) - { - w->flags |= WF_WHITE_BORDER_MASK; - w->Invalidate(); - w = WindowBringToFront(*w); - } - - return w; -} - -/** - * - * rct2: 0x006EE65A - */ -void WindowPushOthersRight(WindowBase& window) -{ - WindowVisitEach([&window](WindowBase* w) { - if (w == &window) - return; - if (w->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT)) - return; - if (w->windowPos.x >= window.windowPos.x + window.width) - return; - if (w->windowPos.x + w->width <= window.windowPos.x) - return; - if (w->windowPos.y >= window.windowPos.y + window.height) - return; - if (w->windowPos.y + w->height <= window.windowPos.y) - return; - - w->Invalidate(); - if (window.windowPos.x + window.width + 13 >= ContextGetWidth()) - return; - auto push_amount = window.windowPos.x + window.width - w->windowPos.x + 3; - w->windowPos.x += push_amount; - w->Invalidate(); - if (w->viewport != nullptr) - w->viewport->pos.x += push_amount; - }); -} - -/** - * - * rct2: 0x006EE6EA - */ -void WindowPushOthersBelow(WindowBase& w1) -{ - // Enumerate through all other windows - WindowVisitEach([&w1](WindowBase* w2) { - if (&w1 == w2) - return; - // ? - if (w2->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT)) - return; - // Check if w2 intersects with w1 - if (w2->windowPos.x > (w1.windowPos.x + w1.width) || w2->windowPos.x + w2->width < w1.windowPos.x) - return; - if (w2->windowPos.y > (w1.windowPos.y + w1.height) || w2->windowPos.y + w2->height < w1.windowPos.y) - return; - - // Check if there is room to push it down - if (w1.windowPos.y + w1.height + 80 >= ContextGetHeight()) - return; - - // Invalidate the window's current area - w2->Invalidate(); - - int32_t push_amount = w1.windowPos.y + w1.height - w2->windowPos.y + 3; - w2->windowPos.y += push_amount; - - // Invalidate the window's new area - w2->Invalidate(); - - // Update viewport position if necessary - if (w2->viewport != nullptr) - w2->viewport->pos.y += push_amount; - }); -} - -/** - * - * rct2: 0x006EE2E4 - */ -WindowBase* WindowGetMain() -{ - for (auto& w : g_window_list) - { - if (w->flags & WF_DEAD) - continue; - if (w->classification == WindowClass::MainWindow) + int32_t prev = Config::Get().general.WindowLimit; + int32_t val = std::clamp(value, kWindowLimitMin, kWindowLimitMax); + Config::Get().general.WindowLimit = val; + Config::Save(); + // Checks if value decreases and then closes surplus + // windows if one sets a limit lower than the number of windows open + if (val < prev) { - return w.get(); + WindowCloseSurplus(val, WindowClass::Options); } } - return nullptr; -} -/** - * - * rct2: 0x006E7C9C - * @param w (esi) - * @param x (eax) - * @param y (ecx) - * @param z (edx) - */ -void WindowScrollToLocation(WindowBase& w, const CoordsXYZ& coords) -{ - WindowUnfollowSprite(w); - if (w.viewport != nullptr) + /** + * Closes the specified window. + * rct2: 0x006ECD4C + * + * @param window The window to close (esi). + */ + void WindowClose(WindowBase& w) { - int16_t height = TileElementHeight(coords); - if (coords.z < height - 16) + w.OnClose(); + + // Remove viewport + w.RemoveViewport(); + + // Invalidate the window (area) + w.Invalidate(); + + w.flags |= WF_DEAD; + } + + template + static void WindowCloseByCondition(TPred pred, uint32_t flags = WindowCloseFlags::None) + { + for (auto it = g_window_list.rbegin(); it != g_window_list.rend(); ++it) { - if (!(w.viewport->flags & VIEWPORT_FLAG_UNDERGROUND_INSIDE)) + auto& wnd = *(*it); + if (wnd.flags & WF_DEAD) + continue; + + if (pred(&wnd)) { - w.viewport->flags |= VIEWPORT_FLAG_UNDERGROUND_INSIDE; - w.Invalidate(); - } - } - else - { - if (w.viewport->flags & VIEWPORT_FLAG_UNDERGROUND_INSIDE) - { - w.viewport->flags &= ~VIEWPORT_FLAG_UNDERGROUND_INSIDE; - w.Invalidate(); - } - } - - auto screenCoords = Translate3DTo2DWithZ(w.viewport->rotation, coords); - - int32_t i = 0; - if (!(gScreenFlags & SCREEN_FLAGS_TITLE_DEMO)) - { - bool found = false; - while (!found) - { - auto x2 = w.viewport->pos.x + static_cast(w.viewport->width * window_scroll_locations[i][0]); - auto y2 = w.viewport->pos.y + static_cast(w.viewport->height * window_scroll_locations[i][1]); - - auto it = WindowGetIterator(&w); - for (; it != g_window_list.end(); it++) + WindowClose(wnd); + if (flags & WindowCloseFlags::CloseSingle) { - auto w2 = (*it).get(); - auto x1 = w2->windowPos.x - 10; - auto y1 = w2->windowPos.y - 10; - if (x2 >= x1 && x2 <= w2->width + x1 + 20) + return; + } + } + } + } + + /** + * Closes all windows with the specified window class. + * rct2: 0x006ECCF4 + * @param cls (cl) with bit 15 set + */ + void WindowCloseByClass(WindowClass cls) + { + WindowCloseByCondition([&](WindowBase* w) -> bool { return w->classification == cls; }); + } + + /** + * Closes all windows with specified window class and number. + * rct2: 0x006ECCF4 + * @param cls (cl) without bit 15 set + * @param number (dx) + */ + void WindowCloseByNumber(WindowClass cls, rct_windownumber number) + { + WindowCloseByCondition( + [cls, number](WindowBase* w) -> bool { return w->classification == cls && w->number == number; }); + } + + // TODO: Refactor this to use variant once the new window class is done. + void WindowCloseByNumber(WindowClass cls, EntityId number) + { + WindowCloseByNumber(cls, static_cast(number.ToUnderlying())); + } + + /** + * Closes the top-most window + * + * rct2: 0x006E403C + */ + void WindowCloseTop() + { + WindowCloseByClass(WindowClass::Dropdown); + + if (gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) + { + if (GetGameState().EditorStep != EditorStep::LandscapeEditor) + return; + } + + auto pred = [](WindowBase* w) -> bool { return !(w->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT)); }; + WindowCloseByCondition(pred, WindowCloseFlags::CloseSingle); + } + + /** + * Closes all open windows + * + * rct2: 0x006EE927 + */ + void WindowCloseAll() + { + WindowCloseByClass(WindowClass::Dropdown); + WindowCloseByCondition([](WindowBase* w) -> bool { return !(w->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT)); }); + } + + void WindowCloseAllExceptClass(WindowClass cls) + { + WindowCloseByClass(WindowClass::Dropdown); + WindowCloseByCondition([cls](WindowBase* w) -> bool { + return w->classification != cls && !(w->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT)); + }); + } + + /** + * Closes all windows, save for those having any of the passed flags. + */ + void WindowCloseAllExceptFlags(uint16_t flags) + { + WindowCloseByCondition([flags](WindowBase* w) -> bool { return !(w->flags & flags); }); + } + + /** + * Closes all windows except the specified window number and class. + * @param number (dx) + * @param cls (cl) without bit 15 set + */ + void WindowCloseAllExceptNumberAndClass(rct_windownumber number, WindowClass cls) + { + WindowCloseByClass(WindowClass::Dropdown); + WindowCloseByCondition([cls, number](WindowBase* w) -> bool { + return (!(w->number == number && w->classification == cls) && !(w->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT))); + }); + } + + /** + * Invalidates the specified window. + * rct2: 0x006EB13A + * + * @param window The window to invalidate (esi). + */ + template + static void WindowInvalidateByCondition(TPred pred) + { + WindowVisitEach([pred](WindowBase* w) { + if (pred(w)) + { + w->Invalidate(); + } + }); + } + + /** + * Invalidates all windows with the specified window class. + * rct2: 0x006EC3AC + * @param cls (al) with bit 14 set + */ + void WindowInvalidateByClass(WindowClass cls) + { + WindowInvalidateByCondition([cls](WindowBase* w) -> bool { return w->classification == cls; }); + } + + /** + * Invalidates all windows with the specified window class and number. + * rct2: 0x006EC3AC + */ + void WindowInvalidateByNumber(WindowClass cls, rct_windownumber number) + { + WindowInvalidateByCondition( + [cls, number](WindowBase* w) -> bool { return w->classification == cls && w->number == number; }); + } + + // TODO: Use variant for this once the window framework is done. + void WindowInvalidateByNumber(WindowClass cls, EntityId id) + { + WindowInvalidateByNumber(cls, static_cast(id.ToUnderlying())); + } + + /** + * Invalidates all windows. + */ + void WindowInvalidateAll() + { + WindowVisitEach([](WindowBase* w) { w->Invalidate(); }); + } + + /** + * Invalidates the specified widget of a window. + * rct2: 0x006EC402 + */ + void WidgetInvalidate(WindowBase& w, WidgetIndex widgetIndex) + { + if (w.widgets.empty()) + { + // This might be called before the window is fully created. + return; + } + + assert(widgetIndex < w.widgets.size()); + + const auto& widget = w.widgets[widgetIndex]; + if (widget.left == -2) + return; + + GfxSetDirtyBlocks({ { w.windowPos + ScreenCoordsXY{ widget.left, widget.top } }, + { w.windowPos + ScreenCoordsXY{ widget.right + 1, widget.bottom + 1 } } }); + } + + template + static void widget_invalidate_by_condition(TPred pred) + { + WindowVisitEach([pred](WindowBase* w) { + if (pred(w)) + { + w->Invalidate(); + } + }); + } + + /** + * Invalidates the specified widget of all windows that match the specified window class. + */ + void WidgetInvalidateByClass(WindowClass cls, WidgetIndex widgetIndex) + { + WindowVisitEach([cls, widgetIndex](WindowBase* w) { + if (w->classification == cls) + { + WidgetInvalidate(*w, widgetIndex); + } + }); + } + + /** + * Invalidates the specified widget of all windows that match the specified window class and number. + * rct2: 0x006EC3AC + */ + void WidgetInvalidateByNumber(WindowClass cls, rct_windownumber number, WidgetIndex widgetIndex) + { + WindowVisitEach([cls, number, widgetIndex](WindowBase* w) { + if (w->classification == cls && w->number == number) + { + WidgetInvalidate(*w, widgetIndex); + } + }); + } + + int32_t WindowGetScrollDataIndex(const WindowBase& w, WidgetIndex widget_index) + { + int32_t i, result; + + result = 0; + for (i = 0; i < widget_index; i++) + { + const auto& widget = w.widgets[i]; + if (widget.type == WindowWidgetType::Scroll) + result++; + } + return result; + } + + /** + * + * rct2: 0x006ECDA4 + */ + WindowBase* WindowBringToFront(WindowBase& w) + { + if (!(w.flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT))) + { + auto itSourcePos = WindowGetIterator(&w); + if (itSourcePos != g_window_list.end()) + { + // Insert in front of the first non-stick-to-front window + auto itDestPos = g_window_list.begin(); + for (auto it = g_window_list.rbegin(); it != g_window_list.rend(); it++) + { + auto& w2 = *it; + if (!(w2->flags & WF_STICK_TO_FRONT)) { - if (y2 >= y1 && y2 <= w2->height + y1 + 20) - { - // window is covering this area, try the next one - i++; - found = false; - break; - } + itDestPos = it.base(); + break; } } - if (it == g_window_list.end()) + + g_window_list.splice(itDestPos, g_window_list, itSourcePos); + w.Invalidate(); + + if (w.windowPos.x + w.width < 20) { - found = true; - } - if (i >= static_cast(std::size(window_scroll_locations))) - { - i = 0; - found = true; + int32_t i = 20 - w.windowPos.x; + w.windowPos.x += i; + if (w.viewport != nullptr) + w.viewport->pos.x += i; + w.Invalidate(); } } } - // rct2: 0x006E7C76 - if (w.viewport_target_sprite.IsNull()) + return &w; + } + + WindowBase* WindowBringToFrontByClassWithFlags(WindowClass cls, uint16_t flags) + { + auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); + WindowBase* w = windowMgr->FindByClass(cls); + if (w != nullptr) { - if (!(w.flags & WF_NO_SCROLLING)) + w->flags |= flags; + w->Invalidate(); + w = WindowBringToFront(*w); + } + + return w; + } + + WindowBase* WindowBringToFrontByClass(WindowClass cls) + { + return WindowBringToFrontByClassWithFlags(cls, WF_WHITE_BORDER_MASK); + } + + /** + * + * rct2: 0x006ED78A + * cls (cl) + * number (dx) + */ + WindowBase* WindowBringToFrontByNumber(WindowClass cls, rct_windownumber number) + { + auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); + WindowBase* w = windowMgr->FindByNumber(cls, number); + if (w != nullptr) + { + w->flags |= WF_WHITE_BORDER_MASK; + w->Invalidate(); + w = WindowBringToFront(*w); + } + + return w; + } + + /** + * + * rct2: 0x006EE65A + */ + void WindowPushOthersRight(WindowBase& window) + { + WindowVisitEach([&window](WindowBase* w) { + if (w == &window) + return; + if (w->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT)) + return; + if (w->windowPos.x >= window.windowPos.x + window.width) + return; + if (w->windowPos.x + w->width <= window.windowPos.x) + return; + if (w->windowPos.y >= window.windowPos.y + window.height) + return; + if (w->windowPos.y + w->height <= window.windowPos.y) + return; + + w->Invalidate(); + if (window.windowPos.x + window.width + 13 >= ContextGetWidth()) + return; + auto push_amount = window.windowPos.x + window.width - w->windowPos.x + 3; + w->windowPos.x += push_amount; + w->Invalidate(); + if (w->viewport != nullptr) + w->viewport->pos.x += push_amount; + }); + } + + /** + * + * rct2: 0x006EE6EA + */ + void WindowPushOthersBelow(WindowBase& w1) + { + // Enumerate through all other windows + WindowVisitEach([&w1](WindowBase* w2) { + if (&w1 == w2) + return; + // ? + if (w2->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT)) + return; + // Check if w2 intersects with w1 + if (w2->windowPos.x > (w1.windowPos.x + w1.width) || w2->windowPos.x + w2->width < w1.windowPos.x) + return; + if (w2->windowPos.y > (w1.windowPos.y + w1.height) || w2->windowPos.y + w2->height < w1.windowPos.y) + return; + + // Check if there is room to push it down + if (w1.windowPos.y + w1.height + 80 >= ContextGetHeight()) + return; + + // Invalidate the window's current area + w2->Invalidate(); + + int32_t push_amount = w1.windowPos.y + w1.height - w2->windowPos.y + 3; + w2->windowPos.y += push_amount; + + // Invalidate the window's new area + w2->Invalidate(); + + // Update viewport position if necessary + if (w2->viewport != nullptr) + w2->viewport->pos.y += push_amount; + }); + } + + /** + * + * rct2: 0x006EE2E4 + */ + WindowBase* WindowGetMain() + { + for (auto& w : g_window_list) + { + if (w->flags & WF_DEAD) + continue; + if (w->classification == WindowClass::MainWindow) { - w.savedViewPos = screenCoords - - ScreenCoordsXY{ static_cast(w.viewport->ViewWidth() * window_scroll_locations[i][0]), - static_cast(w.viewport->ViewHeight() * window_scroll_locations[i][1]) }; - w.flags |= WF_SCROLLING_TO_LOCATION; + return w.get(); } } - } -} - -void WindowViewportGetMapCoordsByCursor( - const WindowBase& w, int32_t* map_x, int32_t* map_y, int32_t* offset_x, int32_t* offset_y) -{ - // Get mouse position to offset against. - auto mouseCoords = ContextGetCursorPositionScaled(); - - // Compute map coordinate by mouse position. - auto viewportPos = w.viewport->ScreenToViewportCoord(mouseCoords); - auto coordsXYZ = ViewportAdjustForMapHeight(viewportPos, w.viewport->rotation); - auto mapCoords = ViewportPosToMapPos(viewportPos, coordsXYZ.z, w.viewport->rotation); - *map_x = mapCoords.x; - *map_y = mapCoords.y; - - // Get viewport coordinates centring around the tile. - int32_t z = TileElementHeight(mapCoords); - - auto centreLoc = centre_2d_coordinates({ mapCoords.x, mapCoords.y, z }, w.viewport); - if (!centreLoc) - { - LOG_ERROR("Invalid location."); - return; - } - - // Rebase mouse position onto centre of window, and compensate for zoom level. - int32_t rebased_x = w.viewport->zoom.ApplyTo(w.width / 2 - mouseCoords.x); - int32_t rebased_y = w.viewport->zoom.ApplyTo(w.height / 2 - mouseCoords.y); - - // Compute cursor offset relative to tile. - *offset_x = w.viewport->zoom.ApplyTo(w.savedViewPos.x - (centreLoc->x + rebased_x)); - *offset_y = w.viewport->zoom.ApplyTo(w.savedViewPos.y - (centreLoc->y + rebased_y)); -} - -void WindowViewportCentreTileAroundCursor(WindowBase& w, int32_t map_x, int32_t map_y, int32_t offset_x, int32_t offset_y) -{ - // Get viewport coordinates centring around the tile. - int32_t z = TileElementHeight({ map_x, map_y }); - auto centreLoc = centre_2d_coordinates({ map_x, map_y, z }, w.viewport); - - if (!centreLoc.has_value()) - { - LOG_ERROR("Invalid location."); - return; - } - - // Get mouse position to offset against. - auto mouseCoords = ContextGetCursorPositionScaled(); - - // Rebase mouse position onto centre of window, and compensate for zoom level. - int32_t rebased_x = w.viewport->zoom.ApplyTo((w.width >> 1) - mouseCoords.x); - int32_t rebased_y = w.viewport->zoom.ApplyTo((w.height >> 1) - mouseCoords.y); - - // Apply offset to the viewport. - w.savedViewPos = { centreLoc->x + rebased_x + w.viewport->zoom.ApplyInversedTo(offset_x), - centreLoc->y + rebased_y + w.viewport->zoom.ApplyInversedTo(offset_y) }; -} - -/** - * For all windows with viewports, ensure they do not have a zoom level less than the minimum. - */ -void WindowCheckAllValidZoom() -{ - WindowVisitEach([](WindowBase* w) { - if (w->viewport != nullptr && w->viewport->zoom < ZoomLevel::min()) - { - WindowZoomSet(*w, ZoomLevel::min(), false); - } - }); -} - -void WindowZoomSet(WindowBase& w, ZoomLevel zoomLevel, bool atCursor) -{ - Viewport* v = w.viewport; - if (v == nullptr) - return; - - zoomLevel = std::clamp(zoomLevel, ZoomLevel::min(), ZoomLevel::max()); - if (v->zoom == zoomLevel) - return; - - // Zooming to cursor? Remember where we're pointing at the moment. - int32_t saved_map_x = 0; - int32_t saved_map_y = 0; - int32_t offset_x = 0; - int32_t offset_y = 0; - if (Config::Get().general.ZoomToCursor && atCursor) - { - WindowViewportGetMapCoordsByCursor(w, &saved_map_x, &saved_map_y, &offset_x, &offset_y); - } - - // Zoom in - while (v->zoom > zoomLevel) - { - v->zoom--; - w.savedViewPos.x += v->ViewWidth() / 2; - w.savedViewPos.y += v->ViewHeight() / 2; - } - - // Zoom out - while (v->zoom < zoomLevel) - { - v->zoom++; - w.savedViewPos.x -= v->ViewWidth() / 4; - w.savedViewPos.y -= v->ViewHeight() / 4; - } - - // Zooming to cursor? Centre around the tile we were hovering over just now. - if (Config::Get().general.ZoomToCursor && atCursor) - { - WindowViewportCentreTileAroundCursor(w, saved_map_x, saved_map_y, offset_x, offset_y); - } - - // HACK: Prevents the redraw from failing when there is - // a window on top of the viewport. - WindowBringToFront(w); - w.Invalidate(); -} - -/** - * Splits a drawing of a window into regions that can be seen and are not hidden - * by other opaque overlapping windows. - */ -void WindowDraw(DrawPixelInfo& dpi, WindowBase& w, int32_t left, int32_t top, int32_t right, int32_t bottom) -{ - if (!WindowIsVisible(w)) - return; - - // Divide the draws up for only the visible regions of the window recursively - auto itPos = WindowGetIterator(&w); - for (auto it = std::next(itPos); it != g_window_list.end(); it++) - { - // Check if this window overlaps w - auto topwindow = it->get(); - if (topwindow->windowPos.x >= right || topwindow->windowPos.y >= bottom) - continue; - if (topwindow->windowPos.x + topwindow->width <= left || topwindow->windowPos.y + topwindow->height <= top) - continue; - if (topwindow->flags & WF_TRANSPARENT) - continue; - - // A window overlaps w, split up the draw into two regions where the window starts to overlap - if (topwindow->windowPos.x > left) - { - // Split draw at topwindow.left - WindowDrawCore(dpi, w, left, top, topwindow->windowPos.x, bottom); - WindowDrawCore(dpi, w, topwindow->windowPos.x, top, right, bottom); - } - else if (topwindow->windowPos.x + topwindow->width < right) - { - // Split draw at topwindow.right - WindowDrawCore(dpi, w, left, top, topwindow->windowPos.x + topwindow->width, bottom); - WindowDrawCore(dpi, w, topwindow->windowPos.x + topwindow->width, top, right, bottom); - } - else if (topwindow->windowPos.y > top) - { - // Split draw at topwindow.top - WindowDrawCore(dpi, w, left, top, right, topwindow->windowPos.y); - WindowDrawCore(dpi, w, left, topwindow->windowPos.y, right, bottom); - } - else if (topwindow->windowPos.y + topwindow->height < bottom) - { - // Split draw at topwindow.bottom - WindowDrawCore(dpi, w, left, top, right, topwindow->windowPos.y + topwindow->height); - WindowDrawCore(dpi, w, left, topwindow->windowPos.y + topwindow->height, right, bottom); - } - - // Drawing for this region should be done now, exit - return; - } - - // No windows overlap - WindowDrawCore(dpi, w, left, top, right, bottom); -} - -/** - * Draws the given window and any other overlapping transparent windows. - */ -static void WindowDrawCore(DrawPixelInfo& dpi, WindowBase& w, int32_t left, int32_t top, int32_t right, int32_t bottom) -{ - // Clamp region - left = std::max(left, w.windowPos.x); - top = std::max(top, w.windowPos.y); - right = std::min(right, w.windowPos.x + w.width); - bottom = std::min(bottom, w.windowPos.y + w.height); - if (left >= right) - return; - if (top >= bottom) - return; - - // Draw the window and any other overlapping transparent windows - for (auto it = WindowGetIterator(&w); it != g_window_list.end(); it++) - { - auto* v = (*it).get(); - if (v->flags & WF_DEAD) - continue; - if ((&w == v || (v->flags & WF_TRANSPARENT)) && WindowIsVisible(*v)) - { - WindowDrawSingle(dpi, *v, left, top, right, bottom); - } - } -} - -static void WindowDrawSingle(DrawPixelInfo& dpi, WindowBase& w, int32_t left, int32_t top, int32_t right, int32_t bottom) -{ - assert(dpi.zoom_level == ZoomLevel{ 0 }); - // Copy dpi so we can crop it - DrawPixelInfo copy = dpi; - - // Clamp left to 0 - int32_t overflow = left - copy.x; - if (overflow > 0) - { - copy.x += overflow; - copy.width -= overflow; - if (copy.width <= 0) - return; - copy.pitch += overflow; - copy.bits += overflow; - } - - // Clamp width to right - overflow = copy.x + copy.width - right; - if (overflow > 0) - { - copy.width -= overflow; - if (copy.width <= 0) - return; - copy.pitch += overflow; - } - - // Clamp top to 0 - overflow = top - copy.y; - if (overflow > 0) - { - copy.y += overflow; - copy.height -= overflow; - if (copy.height <= 0) - return; - copy.bits += copy.LineStride() * overflow; - } - - // Clamp height to bottom - overflow = copy.y + copy.height - bottom; - if (overflow > 0) - { - copy.height -= overflow; - if (copy.height <= 0) - return; - } - - // Invalidate modifies the window colours so first get the correct - // colour before setting the global variables for the string painting - w.OnPrepareDraw(); - - // Text colouring - gCurrentWindowColours[0] = w.colours[0].colour; - gCurrentWindowColours[1] = w.colours[1].colour; - gCurrentWindowColours[2] = w.colours[2].colour; - - w.OnDraw(copy); -} - -bool isToolActive(WindowClass cls) -{ - return InputTestFlag(INPUT_FLAG_TOOL_ACTIVE) && gCurrentToolWidget.window_classification == cls; -} - -bool isToolActive(WindowClass cls, rct_windownumber number) -{ - return isToolActive(cls) && gCurrentToolWidget.window_number == number; -} - -bool isToolActive(WindowClass cls, WidgetIndex widgetIndex) -{ - return isToolActive(cls) && gCurrentToolWidget.widget_index == widgetIndex; -} - -bool isToolActive(WindowClass cls, WidgetIndex widgetIndex, rct_windownumber number) -{ - return isToolActive(cls, widgetIndex) && gCurrentToolWidget.window_number == number; -} - -bool isToolActive(const WindowBase& w, WidgetIndex widgetIndex) -{ - return isToolActive(w.classification, widgetIndex, w.number); -} - -/** - * - * rct2: 0x006EE212 - * - * @param tool (al) - * @param widgetIndex (dx) - * @param w (esi) - */ -bool ToolSet(const WindowBase& w, WidgetIndex widgetIndex, Tool tool) -{ - if (InputTestFlag(INPUT_FLAG_TOOL_ACTIVE)) - { - if (w.classification == gCurrentToolWidget.window_classification && w.number == gCurrentToolWidget.window_number - && widgetIndex == gCurrentToolWidget.widget_index) - { - ToolCancel(); - return true; - } - - ToolCancel(); - } - - InputSetFlag(INPUT_FLAG_TOOL_ACTIVE, true); - InputSetFlag(INPUT_FLAG_4, false); - InputSetFlag(INPUT_FLAG_6, false); - gCurrentToolId = tool; - gCurrentToolWidget.window_classification = w.classification; - gCurrentToolWidget.window_number = w.number; - gCurrentToolWidget.widget_index = widgetIndex; - return false; -} - -/** - * - * rct2: 0x006EE281 - */ -void ToolCancel() -{ - if (InputTestFlag(INPUT_FLAG_TOOL_ACTIVE)) - { - InputSetFlag(INPUT_FLAG_TOOL_ACTIVE, false); - - MapInvalidateSelectionRect(); - MapInvalidateMapSelectionTiles(); - - // Reset map selection - gMapSelectFlags = 0; - - if (gCurrentToolWidget.widget_index != -1) - { - // Invalidate tool widget - WidgetInvalidateByNumber( - gCurrentToolWidget.window_classification, gCurrentToolWidget.window_number, gCurrentToolWidget.widget_index); - - // Abort tool event - auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); - WindowBase* w = windowMgr->FindByNumber(gCurrentToolWidget.window_classification, gCurrentToolWidget.window_number); - if (w != nullptr) - w->OnToolAbort(gCurrentToolWidget.widget_index); - } - } -} - -/** - * rct2: 0x0066B905 - */ -void WindowResizeGui(int32_t width, int32_t height) -{ - WindowResizeGuiScenarioEditor(width, height); - if (gScreenFlags & SCREEN_FLAGS_EDITOR) - return; - - auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); - WindowBase* titleWind = windowMgr->FindByClass(WindowClass::TitleMenu); - if (titleWind != nullptr) - { - titleWind->windowPos.x = (width - titleWind->width) / 2; - titleWind->windowPos.y = height - 182; - } - - WindowBase* versionWind = windowMgr->FindByClass(WindowClass::TitleVersion); - if (versionWind != nullptr) - versionWind->windowPos.y = height - 30; - - WindowBase* exitWind = windowMgr->FindByClass(WindowClass::TitleExit); - if (exitWind != nullptr) - { - exitWind->windowPos.x = width - 40; - exitWind->windowPos.y = height - 64; - } - - WindowBase* optionsWind = windowMgr->FindByClass(WindowClass::TitleOptions); - if (optionsWind != nullptr) - { - optionsWind->windowPos.x = width - 80; - } - - // Keep options window centred after a resize - WindowBase* optionsWindow = windowMgr->FindByClass(WindowClass::Options); - if (optionsWindow != nullptr) - { - optionsWindow->windowPos.x = (ContextGetWidth() - optionsWindow->width) / 2; - optionsWindow->windowPos.y = (ContextGetHeight() - optionsWindow->height) / 2; - } - - // Keep progress bar window centred after a resize - WindowBase* ProgressWindow = windowMgr->FindByClass(WindowClass::ProgressWindow); - if (ProgressWindow != nullptr) - { - ProgressWindow->windowPos.x = (ContextGetWidth() - ProgressWindow->width) / 2; - ProgressWindow->windowPos.y = (ContextGetHeight() - ProgressWindow->height) / 2; - } - - GfxInvalidateScreen(); -} - -/** - * rct2: 0x0066F0DD - */ -void WindowResizeGuiScenarioEditor(int32_t width, int32_t height) -{ - auto* mainWind = WindowGetMain(); - if (mainWind != nullptr) - { - Viewport* viewport = mainWind->viewport; - mainWind->width = width; - mainWind->height = height; - viewport->width = width; - viewport->height = height; - if (mainWind->widgets != nullptr && mainWind->widgets[WC_MAIN_WINDOW__0].type == WindowWidgetType::Viewport) - { - mainWind->widgets[WC_MAIN_WINDOW__0].right = width; - mainWind->widgets[WC_MAIN_WINDOW__0].bottom = height; - } - } - - auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); - - WindowBase* topWind = windowMgr->FindByClass(WindowClass::TopToolbar); - if (topWind != nullptr) - { - topWind->width = std::max(640, width); - } - - WindowBase* bottomWind = windowMgr->FindByClass(WindowClass::BottomToolbar); - if (bottomWind != nullptr) - { - bottomWind->windowPos.y = height - 32; - bottomWind->width = std::max(640, width); - } -} - -/** - * - * rct2: 0x006CBCC3 - */ -void WindowCloseConstructionWindows() -{ - WindowCloseByClass(WindowClass::RideConstruction); - WindowCloseByClass(WindowClass::Footpath); - WindowCloseByClass(WindowClass::TrackDesignList); - WindowCloseByClass(WindowClass::TrackDesignPlace); -} - -/** - * Update zoom based volume attenuation for ride music and clear music list. - * rct2: 0x006BC348 - */ -void WindowUpdateViewportRideMusic() -{ - RideAudio::ClearAllViewportInstances(); - g_music_tracking_viewport = nullptr; - - for (auto it = g_window_list.rbegin(); it != g_window_list.rend(); it++) - { - auto w = it->get(); - auto viewport = w->viewport; - if (viewport == nullptr || !(viewport->flags & VIEWPORT_FLAG_SOUND_ON)) - continue; - - g_music_tracking_viewport = viewport; - gWindowAudioExclusive = w; - - if (viewport->zoom <= ZoomLevel{ 0 }) - Audio::gVolumeAdjustZoom = 0; - else if (viewport->zoom == ZoomLevel{ 1 }) - Audio::gVolumeAdjustZoom = 30; - else - Audio::gVolumeAdjustZoom = 60; - break; - } -} - -/** - * - * rct2: 0x006EE3C3 - */ -void TextinputCancel() -{ - WindowCloseByClass(WindowClass::Textinput); -} - -bool WindowIsVisible(WindowBase& w) -{ - // w->visibility is used to prevent repeat calculations within an iteration by caching the result - - if (w.visibility == VisibilityCache::Visible) - return true; - if (w.visibility == VisibilityCache::Covered) - return false; - - // only consider viewports, consider the main window always visible - if (w.viewport == nullptr || w.classification == WindowClass::MainWindow) - { - // default to previous behaviour - w.visibility = VisibilityCache::Visible; - return true; - } - - // start from the window above the current - auto itPos = WindowGetIterator(&w); - for (auto it = std::next(itPos); it != g_window_list.end(); it++) - { - auto& w_other = *(*it); - if (w_other.flags & WF_DEAD) - continue; - - // if covered by a higher window, no rendering needed - if (w_other.windowPos.x <= w.windowPos.x && w_other.windowPos.y <= w.windowPos.y - && w_other.windowPos.x + w_other.width >= w.windowPos.x + w.width - && w_other.windowPos.y + w_other.height >= w.windowPos.y + w.height) - { - w.visibility = VisibilityCache::Covered; - w.viewport->visibility = VisibilityCache::Covered; - return false; - } - } - - // default to previous behaviour - w.visibility = VisibilityCache::Visible; - w.viewport->visibility = VisibilityCache::Visible; - return true; -} - -/** - * - * rct2: 0x006E7499 - * left (ax) - * top (bx) - * right (dx) - * bottom (bp) - */ -void WindowDrawAll(DrawPixelInfo& dpi, int32_t left, int32_t top, int32_t right, int32_t bottom) -{ - auto windowDPI = dpi.Crop({ left, top }, { right - left, bottom - top }); - WindowVisitEach([&windowDPI, left, top, right, bottom](WindowBase* w) { - if (w->flags & WF_TRANSPARENT) - return; - if (right <= w->windowPos.x || bottom <= w->windowPos.y) - return; - if (left >= w->windowPos.x + w->width || top >= w->windowPos.y + w->height) - return; - WindowDraw(windowDPI, *w, left, top, right, bottom); - }); -} - -Viewport* WindowGetPreviousViewport(Viewport* current) -{ - bool foundPrevious = (current == nullptr); - for (auto it = g_window_list.rbegin(); it != g_window_list.rend(); it++) - { - auto& w = **it; - if (w.flags & WF_DEAD) - continue; - if (w.viewport != nullptr) - { - if (foundPrevious) - { - return w.viewport; - } - if (w.viewport == current) - { - foundPrevious = true; - } - } - } - return nullptr; -} - -void WindowResetVisibilities() -{ - // reset window visibility status to unknown - WindowVisitEach([](WindowBase* w) { - w->visibility = VisibilityCache::Unknown; - if (w->viewport != nullptr) - { - w->viewport->visibility = VisibilityCache::Unknown; - } - }); -} - -void WindowInitAll() -{ - WindowCloseAllExceptFlags(0); -} - -void WindowFollowSprite(WindowBase& w, EntityId spriteIndex) -{ - if (spriteIndex.ToUnderlying() < MAX_ENTITIES || spriteIndex.IsNull()) - { - w.viewport_smart_follow_sprite = spriteIndex; - } -} - -void WindowUnfollowSprite(WindowBase& w) -{ - w.viewport_smart_follow_sprite = EntityId::GetNull(); - w.viewport_target_sprite = EntityId::GetNull(); -} - -Viewport* WindowGetViewport(WindowBase* w) -{ - if (w == nullptr) - { return nullptr; } - return w->viewport; -} + /** + * + * rct2: 0x006E7C9C + * @param w (esi) + * @param x (eax) + * @param y (ecx) + * @param z (edx) + */ + void WindowScrollToLocation(WindowBase& w, const CoordsXYZ& coords) + { + WindowUnfollowSprite(w); + if (w.viewport != nullptr) + { + int16_t height = TileElementHeight(coords); + if (coords.z < height - 16) + { + if (!(w.viewport->flags & VIEWPORT_FLAG_UNDERGROUND_INSIDE)) + { + w.viewport->flags |= VIEWPORT_FLAG_UNDERGROUND_INSIDE; + w.Invalidate(); + } + } + else + { + if (w.viewport->flags & VIEWPORT_FLAG_UNDERGROUND_INSIDE) + { + w.viewport->flags &= ~VIEWPORT_FLAG_UNDERGROUND_INSIDE; + w.Invalidate(); + } + } + + auto screenCoords = Translate3DTo2DWithZ(w.viewport->rotation, coords); + + int32_t i = 0; + if (!(gScreenFlags & SCREEN_FLAGS_TITLE_DEMO)) + { + bool found = false; + while (!found) + { + auto x2 = w.viewport->pos.x + static_cast(w.viewport->width * window_scroll_locations[i][0]); + auto y2 = w.viewport->pos.y + static_cast(w.viewport->height * window_scroll_locations[i][1]); + + auto it = WindowGetIterator(&w); + for (; it != g_window_list.end(); it++) + { + auto w2 = (*it).get(); + auto x1 = w2->windowPos.x - 10; + auto y1 = w2->windowPos.y - 10; + if (x2 >= x1 && x2 <= w2->width + x1 + 20) + { + if (y2 >= y1 && y2 <= w2->height + y1 + 20) + { + // window is covering this area, try the next one + i++; + found = false; + break; + } + } + } + if (it == g_window_list.end()) + { + found = true; + } + if (i >= static_cast(std::size(window_scroll_locations))) + { + i = 0; + found = true; + } + } + } + // rct2: 0x006E7C76 + if (w.viewport_target_sprite.IsNull()) + { + if (!(w.flags & WF_NO_SCROLLING)) + { + w.savedViewPos = screenCoords + - ScreenCoordsXY{ static_cast(w.viewport->ViewWidth() * window_scroll_locations[i][0]), + static_cast(w.viewport->ViewHeight() * window_scroll_locations[i][1]) }; + w.flags |= WF_SCROLLING_TO_LOCATION; + } + } + } + } + + void WindowViewportGetMapCoordsByCursor( + const WindowBase& w, int32_t* map_x, int32_t* map_y, int32_t* offset_x, int32_t* offset_y) + { + // Get mouse position to offset against. + auto mouseCoords = ContextGetCursorPositionScaled(); + + // Compute map coordinate by mouse position. + auto viewportPos = w.viewport->ScreenToViewportCoord(mouseCoords); + auto coordsXYZ = ViewportAdjustForMapHeight(viewportPos, w.viewport->rotation); + auto mapCoords = ViewportPosToMapPos(viewportPos, coordsXYZ.z, w.viewport->rotation); + *map_x = mapCoords.x; + *map_y = mapCoords.y; + + // Get viewport coordinates centring around the tile. + int32_t z = TileElementHeight(mapCoords); + + auto centreLoc = centre_2d_coordinates({ mapCoords.x, mapCoords.y, z }, w.viewport); + if (!centreLoc) + { + LOG_ERROR("Invalid location."); + return; + } + + // Rebase mouse position onto centre of window, and compensate for zoom level. + int32_t rebased_x = w.viewport->zoom.ApplyTo(w.width / 2 - mouseCoords.x); + int32_t rebased_y = w.viewport->zoom.ApplyTo(w.height / 2 - mouseCoords.y); + + // Compute cursor offset relative to tile. + *offset_x = w.viewport->zoom.ApplyTo(w.savedViewPos.x - (centreLoc->x + rebased_x)); + *offset_y = w.viewport->zoom.ApplyTo(w.savedViewPos.y - (centreLoc->y + rebased_y)); + } + + void WindowViewportCentreTileAroundCursor(WindowBase& w, int32_t map_x, int32_t map_y, int32_t offset_x, int32_t offset_y) + { + // Get viewport coordinates centring around the tile. + int32_t z = TileElementHeight({ map_x, map_y }); + auto centreLoc = centre_2d_coordinates({ map_x, map_y, z }, w.viewport); + + if (!centreLoc.has_value()) + { + LOG_ERROR("Invalid location."); + return; + } + + // Get mouse position to offset against. + auto mouseCoords = ContextGetCursorPositionScaled(); + + // Rebase mouse position onto centre of window, and compensate for zoom level. + int32_t rebased_x = w.viewport->zoom.ApplyTo((w.width >> 1) - mouseCoords.x); + int32_t rebased_y = w.viewport->zoom.ApplyTo((w.height >> 1) - mouseCoords.y); + + // Apply offset to the viewport. + w.savedViewPos = { centreLoc->x + rebased_x + w.viewport->zoom.ApplyInversedTo(offset_x), + centreLoc->y + rebased_y + w.viewport->zoom.ApplyInversedTo(offset_y) }; + } + + /** + * For all windows with viewports, ensure they do not have a zoom level less than the minimum. + */ + void WindowCheckAllValidZoom() + { + WindowVisitEach([](WindowBase* w) { + if (w->viewport != nullptr && w->viewport->zoom < ZoomLevel::min()) + { + WindowZoomSet(*w, ZoomLevel::min(), false); + } + }); + } + + void WindowZoomSet(WindowBase& w, ZoomLevel zoomLevel, bool atCursor) + { + Viewport* v = w.viewport; + if (v == nullptr) + return; + + zoomLevel = std::clamp(zoomLevel, ZoomLevel::min(), ZoomLevel::max()); + if (v->zoom == zoomLevel) + return; + + // Zooming to cursor? Remember where we're pointing at the moment. + int32_t saved_map_x = 0; + int32_t saved_map_y = 0; + int32_t offset_x = 0; + int32_t offset_y = 0; + if (Config::Get().general.ZoomToCursor && atCursor) + { + WindowViewportGetMapCoordsByCursor(w, &saved_map_x, &saved_map_y, &offset_x, &offset_y); + } + + // Zoom in + while (v->zoom > zoomLevel) + { + v->zoom--; + w.savedViewPos.x += v->ViewWidth() / 2; + w.savedViewPos.y += v->ViewHeight() / 2; + } + + // Zoom out + while (v->zoom < zoomLevel) + { + v->zoom++; + w.savedViewPos.x -= v->ViewWidth() / 4; + w.savedViewPos.y -= v->ViewHeight() / 4; + } + + // Zooming to cursor? Centre around the tile we were hovering over just now. + if (Config::Get().general.ZoomToCursor && atCursor) + { + WindowViewportCentreTileAroundCursor(w, saved_map_x, saved_map_y, offset_x, offset_y); + } + + // HACK: Prevents the redraw from failing when there is + // a window on top of the viewport. + WindowBringToFront(w); + w.Invalidate(); + } + + /** + * Splits a drawing of a window into regions that can be seen and are not hidden + * by other opaque overlapping windows. + */ + void WindowDraw(DrawPixelInfo& dpi, WindowBase& w, int32_t left, int32_t top, int32_t right, int32_t bottom) + { + if (!WindowIsVisible(w)) + return; + + // Divide the draws up for only the visible regions of the window recursively + auto itPos = WindowGetIterator(&w); + for (auto it = std::next(itPos); it != g_window_list.end(); it++) + { + // Check if this window overlaps w + auto topwindow = it->get(); + if (topwindow->windowPos.x >= right || topwindow->windowPos.y >= bottom) + continue; + if (topwindow->windowPos.x + topwindow->width <= left || topwindow->windowPos.y + topwindow->height <= top) + continue; + if (topwindow->flags & WF_TRANSPARENT) + continue; + + // A window overlaps w, split up the draw into two regions where the window starts to overlap + if (topwindow->windowPos.x > left) + { + // Split draw at topwindow.left + WindowDrawCore(dpi, w, left, top, topwindow->windowPos.x, bottom); + WindowDrawCore(dpi, w, topwindow->windowPos.x, top, right, bottom); + } + else if (topwindow->windowPos.x + topwindow->width < right) + { + // Split draw at topwindow.right + WindowDrawCore(dpi, w, left, top, topwindow->windowPos.x + topwindow->width, bottom); + WindowDrawCore(dpi, w, topwindow->windowPos.x + topwindow->width, top, right, bottom); + } + else if (topwindow->windowPos.y > top) + { + // Split draw at topwindow.top + WindowDrawCore(dpi, w, left, top, right, topwindow->windowPos.y); + WindowDrawCore(dpi, w, left, topwindow->windowPos.y, right, bottom); + } + else if (topwindow->windowPos.y + topwindow->height < bottom) + { + // Split draw at topwindow.bottom + WindowDrawCore(dpi, w, left, top, right, topwindow->windowPos.y + topwindow->height); + WindowDrawCore(dpi, w, left, topwindow->windowPos.y + topwindow->height, right, bottom); + } + + // Drawing for this region should be done now, exit + return; + } + + // No windows overlap + WindowDrawCore(dpi, w, left, top, right, bottom); + } + + /** + * Draws the given window and any other overlapping transparent windows. + */ + static void WindowDrawCore(DrawPixelInfo& dpi, WindowBase& w, int32_t left, int32_t top, int32_t right, int32_t bottom) + { + // Clamp region + left = std::max(left, w.windowPos.x); + top = std::max(top, w.windowPos.y); + right = std::min(right, w.windowPos.x + w.width); + bottom = std::min(bottom, w.windowPos.y + w.height); + if (left >= right) + return; + if (top >= bottom) + return; + + // Draw the window and any other overlapping transparent windows + for (auto it = WindowGetIterator(&w); it != g_window_list.end(); it++) + { + auto* v = (*it).get(); + if (v->flags & WF_DEAD) + continue; + if ((&w == v || (v->flags & WF_TRANSPARENT)) && WindowIsVisible(*v)) + { + WindowDrawSingle(dpi, *v, left, top, right, bottom); + } + } + } + + static void WindowDrawSingle(DrawPixelInfo& dpi, WindowBase& w, int32_t left, int32_t top, int32_t right, int32_t bottom) + { + assert(dpi.zoom_level == ZoomLevel{ 0 }); + // Copy dpi so we can crop it + DrawPixelInfo copy = dpi; + + // Clamp left to 0 + int32_t overflow = left - copy.x; + if (overflow > 0) + { + copy.x += overflow; + copy.width -= overflow; + if (copy.width <= 0) + return; + copy.pitch += overflow; + copy.bits += overflow; + } + + // Clamp width to right + overflow = copy.x + copy.width - right; + if (overflow > 0) + { + copy.width -= overflow; + if (copy.width <= 0) + return; + copy.pitch += overflow; + } + + // Clamp top to 0 + overflow = top - copy.y; + if (overflow > 0) + { + copy.y += overflow; + copy.height -= overflow; + if (copy.height <= 0) + return; + copy.bits += copy.LineStride() * overflow; + } + + // Clamp height to bottom + overflow = copy.y + copy.height - bottom; + if (overflow > 0) + { + copy.height -= overflow; + if (copy.height <= 0) + return; + } + + // Invalidate modifies the window colours so first get the correct + // colour before setting the global variables for the string painting + w.OnPrepareDraw(); + + // Text colouring + gCurrentWindowColours[0] = w.colours[0].colour; + gCurrentWindowColours[1] = w.colours[1].colour; + gCurrentWindowColours[2] = w.colours[2].colour; + + w.OnDraw(copy); + } + + bool isToolActive(WindowClass cls) + { + return InputTestFlag(INPUT_FLAG_TOOL_ACTIVE) && gCurrentToolWidget.window_classification == cls; + } + + bool isToolActive(WindowClass cls, rct_windownumber number) + { + return isToolActive(cls) && gCurrentToolWidget.window_number == number; + } + + bool isToolActive(WindowClass cls, WidgetIndex widgetIndex) + { + return isToolActive(cls) && gCurrentToolWidget.widget_index == widgetIndex; + } + + bool isToolActive(WindowClass cls, WidgetIndex widgetIndex, rct_windownumber number) + { + return isToolActive(cls, widgetIndex) && gCurrentToolWidget.window_number == number; + } + + bool isToolActive(const WindowBase& w, WidgetIndex widgetIndex) + { + return isToolActive(w.classification, widgetIndex, w.number); + } + + /** + * + * rct2: 0x006EE212 + * + * @param tool (al) + * @param widgetIndex (dx) + * @param w (esi) + */ + bool ToolSet(const WindowBase& w, WidgetIndex widgetIndex, Tool tool) + { + if (InputTestFlag(INPUT_FLAG_TOOL_ACTIVE)) + { + if (w.classification == gCurrentToolWidget.window_classification && w.number == gCurrentToolWidget.window_number + && widgetIndex == gCurrentToolWidget.widget_index) + { + ToolCancel(); + return true; + } + + ToolCancel(); + } + + InputSetFlag(INPUT_FLAG_TOOL_ACTIVE, true); + InputSetFlag(INPUT_FLAG_4, false); + InputSetFlag(INPUT_FLAG_6, false); + gCurrentToolId = tool; + gCurrentToolWidget.window_classification = w.classification; + gCurrentToolWidget.window_number = w.number; + gCurrentToolWidget.widget_index = widgetIndex; + return false; + } + + /** + * + * rct2: 0x006EE281 + */ + void ToolCancel() + { + if (InputTestFlag(INPUT_FLAG_TOOL_ACTIVE)) + { + InputSetFlag(INPUT_FLAG_TOOL_ACTIVE, false); + + MapInvalidateSelectionRect(); + MapInvalidateMapSelectionTiles(); + + // Reset map selection + gMapSelectFlags = 0; + + if (gCurrentToolWidget.widget_index != kWidgetIndexNull) + { + // Invalidate tool widget + WidgetInvalidateByNumber( + gCurrentToolWidget.window_classification, gCurrentToolWidget.window_number, + gCurrentToolWidget.widget_index); + + // Abort tool event + auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); + WindowBase* w = windowMgr->FindByNumber( + gCurrentToolWidget.window_classification, gCurrentToolWidget.window_number); + if (w != nullptr) + w->OnToolAbort(gCurrentToolWidget.widget_index); + } + } + } + + /** + * rct2: 0x0066B905 + */ + void WindowResizeGui(int32_t width, int32_t height) + { + WindowResizeGuiScenarioEditor(width, height); + if (gScreenFlags & SCREEN_FLAGS_EDITOR) + return; + + auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); + WindowBase* titleWind = windowMgr->FindByClass(WindowClass::TitleMenu); + if (titleWind != nullptr) + { + titleWind->windowPos.x = (width - titleWind->width) / 2; + titleWind->windowPos.y = height - 182; + } + + WindowBase* versionWind = windowMgr->FindByClass(WindowClass::TitleVersion); + if (versionWind != nullptr) + versionWind->windowPos.y = height - 30; + + WindowBase* exitWind = windowMgr->FindByClass(WindowClass::TitleExit); + if (exitWind != nullptr) + { + exitWind->windowPos.x = width - 40; + exitWind->windowPos.y = height - 64; + } + + WindowBase* optionsWind = windowMgr->FindByClass(WindowClass::TitleOptions); + if (optionsWind != nullptr) + { + optionsWind->windowPos.x = width - 80; + } + + // Keep options window centred after a resize + WindowBase* optionsWindow = windowMgr->FindByClass(WindowClass::Options); + if (optionsWindow != nullptr) + { + optionsWindow->windowPos.x = (ContextGetWidth() - optionsWindow->width) / 2; + optionsWindow->windowPos.y = (ContextGetHeight() - optionsWindow->height) / 2; + } + + // Keep progress bar window centred after a resize + WindowBase* ProgressWindow = windowMgr->FindByClass(WindowClass::ProgressWindow); + if (ProgressWindow != nullptr) + { + ProgressWindow->windowPos.x = (ContextGetWidth() - ProgressWindow->width) / 2; + ProgressWindow->windowPos.y = (ContextGetHeight() - ProgressWindow->height) / 2; + } + + GfxInvalidateScreen(); + } + + /** + * rct2: 0x0066F0DD + */ + void WindowResizeGuiScenarioEditor(int32_t width, int32_t height) + { + auto* mainWind = WindowGetMain(); + if (mainWind != nullptr) + { + Viewport* viewport = mainWind->viewport; + mainWind->width = width; + mainWind->height = height; + viewport->width = width; + viewport->height = height; + if (!mainWind->widgets.empty() && mainWind->widgets[WC_MAIN_WINDOW__0].type == WindowWidgetType::Viewport) + { + mainWind->widgets[WC_MAIN_WINDOW__0].right = width; + mainWind->widgets[WC_MAIN_WINDOW__0].bottom = height; + } + } + + auto* windowMgr = GetContext()->GetUiContext()->GetWindowManager(); + + WindowBase* topWind = windowMgr->FindByClass(WindowClass::TopToolbar); + if (topWind != nullptr) + { + topWind->width = std::max(640, width); + } + + WindowBase* bottomWind = windowMgr->FindByClass(WindowClass::BottomToolbar); + if (bottomWind != nullptr) + { + bottomWind->windowPos.y = height - 32; + bottomWind->width = std::max(640, width); + } + } + + /** + * + * rct2: 0x006CBCC3 + */ + void WindowCloseConstructionWindows() + { + WindowCloseByClass(WindowClass::RideConstruction); + WindowCloseByClass(WindowClass::Footpath); + WindowCloseByClass(WindowClass::TrackDesignList); + WindowCloseByClass(WindowClass::TrackDesignPlace); + } + + /** + * Update zoom based volume attenuation for ride music and clear music list. + * rct2: 0x006BC348 + */ + void WindowUpdateViewportRideMusic() + { + RideAudio::ClearAllViewportInstances(); + g_music_tracking_viewport = nullptr; + + for (auto it = g_window_list.rbegin(); it != g_window_list.rend(); it++) + { + auto w = it->get(); + auto viewport = w->viewport; + if (viewport == nullptr || !(viewport->flags & VIEWPORT_FLAG_SOUND_ON)) + continue; + + g_music_tracking_viewport = viewport; + gWindowAudioExclusive = w; + + if (viewport->zoom <= ZoomLevel{ 0 }) + Audio::gVolumeAdjustZoom = 0; + else if (viewport->zoom == ZoomLevel{ 1 }) + Audio::gVolumeAdjustZoom = 30; + else + Audio::gVolumeAdjustZoom = 60; + break; + } + } + + /** + * + * rct2: 0x006EE3C3 + */ + void TextinputCancel() + { + WindowCloseByClass(WindowClass::Textinput); + } + + bool WindowIsVisible(WindowBase& w) + { + // w->visibility is used to prevent repeat calculations within an iteration by caching the result + + if (w.visibility == VisibilityCache::Visible) + return true; + if (w.visibility == VisibilityCache::Covered) + return false; + + // only consider viewports, consider the main window always visible + if (w.viewport == nullptr || w.classification == WindowClass::MainWindow) + { + // default to previous behaviour + w.visibility = VisibilityCache::Visible; + return true; + } + + // start from the window above the current + auto itPos = WindowGetIterator(&w); + for (auto it = std::next(itPos); it != g_window_list.end(); it++) + { + auto& w_other = *(*it); + if (w_other.flags & WF_DEAD) + continue; + + // if covered by a higher window, no rendering needed + if (w_other.windowPos.x <= w.windowPos.x && w_other.windowPos.y <= w.windowPos.y + && w_other.windowPos.x + w_other.width >= w.windowPos.x + w.width + && w_other.windowPos.y + w_other.height >= w.windowPos.y + w.height) + { + w.visibility = VisibilityCache::Covered; + w.viewport->visibility = VisibilityCache::Covered; + return false; + } + } + + // default to previous behaviour + w.visibility = VisibilityCache::Visible; + w.viewport->visibility = VisibilityCache::Visible; + return true; + } + + /** + * + * rct2: 0x006E7499 + * left (ax) + * top (bx) + * right (dx) + * bottom (bp) + */ + void WindowDrawAll(DrawPixelInfo& dpi, int32_t left, int32_t top, int32_t right, int32_t bottom) + { + auto windowDPI = dpi.Crop({ left, top }, { right - left, bottom - top }); + WindowVisitEach([&windowDPI, left, top, right, bottom](WindowBase* w) { + if (w->flags & WF_TRANSPARENT) + return; + if (right <= w->windowPos.x || bottom <= w->windowPos.y) + return; + if (left >= w->windowPos.x + w->width || top >= w->windowPos.y + w->height) + return; + WindowDraw(windowDPI, *w, left, top, right, bottom); + }); + } + + Viewport* WindowGetPreviousViewport(Viewport* current) + { + bool foundPrevious = (current == nullptr); + for (auto it = g_window_list.rbegin(); it != g_window_list.rend(); it++) + { + auto& w = **it; + if (w.flags & WF_DEAD) + continue; + if (w.viewport != nullptr) + { + if (foundPrevious) + { + return w.viewport; + } + if (w.viewport == current) + { + foundPrevious = true; + } + } + } + return nullptr; + } + + void WindowResetVisibilities() + { + // reset window visibility status to unknown + WindowVisitEach([](WindowBase* w) { + w->visibility = VisibilityCache::Unknown; + if (w->viewport != nullptr) + { + w->viewport->visibility = VisibilityCache::Unknown; + } + }); + } + + void WindowInitAll() + { + WindowCloseAllExceptFlags(0); + } + + void WindowFollowSprite(WindowBase& w, EntityId spriteIndex) + { + if (spriteIndex.ToUnderlying() < MAX_ENTITIES || spriteIndex.IsNull()) + { + w.viewport_smart_follow_sprite = spriteIndex; + } + } + + void WindowUnfollowSprite(WindowBase& w) + { + w.viewport_smart_follow_sprite = EntityId::GetNull(); + w.viewport_target_sprite = EntityId::GetNull(); + } + + Viewport* WindowGetViewport(WindowBase* w) + { + if (w == nullptr) + { + return nullptr; + } + + return w->viewport; + } +} // namespace OpenRCT2 diff --git a/src/openrct2/interface/Window.h b/src/openrct2/interface/Window.h index 72c8446e25..668e9445d8 100644 --- a/src/openrct2/interface/Window.h +++ b/src/openrct2/interface/Window.h @@ -11,303 +11,202 @@ #include "../Identifiers.h" #include "../core/EnumUtils.hpp" -#include "../drawing/ImageId.hpp" -#include "../localisation/Formatter.h" -#include "../ride/RideTypes.h" #include "../windows/TileInspectorGlobals.h" #include "../world/Location.hpp" -#include "../world/ScenerySelection.h" #include "Colour.h" #include "Widget.h" #include "WindowClasses.h" #include "ZoomLevel.h" #include -#include #include #include -#include #include struct DrawPixelInfo; -struct WindowBase; struct TrackDesignFileRef; struct ScenarioIndexEntry; -struct WindowCloseModifier; enum class VisibilityCache : uint8_t; enum class CursorID : uint8_t; enum class CloseWindowModifier : uint8_t; -using rct_windownumber = uint16_t; - namespace OpenRCT2 { + using rct_windownumber = int16_t; + + struct WindowBase; + struct WindowCloseModifier; + enum class RideConstructionState : uint8_t; -} -struct WindowIdentifier -{ - WindowClass classification; - rct_windownumber number; -}; - -struct WidgetIdentifier -{ - WindowIdentifier window; - WidgetIndex widget_index; -}; - -extern WindowCloseModifier gLastCloseModifier; - -using WidgetFlags = uint32_t; -namespace OpenRCT2::WIDGET_FLAGS -{ - const WidgetFlags TEXT_IS_STRING = 1 << 0; - const WidgetFlags IS_PRESSED = 1 << 2; - const WidgetFlags IS_DISABLED = 1 << 3; - const WidgetFlags TOOLTIP_IS_STRING = 1 << 4; - const WidgetFlags IS_HIDDEN = 1 << 5; - const WidgetFlags IS_HOLDABLE = 1 << 6; -} // namespace OpenRCT2::WIDGET_FLAGS - -enum class WindowWidgetType : uint8_t; - -struct Widget -{ - WindowWidgetType type; - uint8_t colour; - int16_t left; - int16_t right; - int16_t top; - int16_t bottom; - union + struct WindowIdentifier { - uint32_t content; - ImageId image; - StringId text; - utf8* string; + WindowClass classification; + rct_windownumber number; }; - StringId tooltip; - // New properties - WidgetFlags flags{}; - utf8* sztooltip{}; - - int16_t width() const + struct WidgetIdentifier { - return right - left; - } + WindowIdentifier window; + WidgetIndex widget_index; + }; - int16_t height() const + extern WindowCloseModifier gLastCloseModifier; + + /** + * Viewport structure + */ + struct Viewport { - return bottom - top; - } + int32_t width{}; + int32_t height{}; + ScreenCoordsXY pos{}; + ScreenCoordsXY viewPos{}; + uint32_t flags{}; + ZoomLevel zoom{}; + uint8_t rotation{}; + VisibilityCache visibility{}; - int16_t midX() const - { - return (left + right) / 2; - } - - int16_t midY() const - { - return (top + bottom) / 2; - } - - int16_t textTop() const - { - if (height() >= 10) - return std::max(top, top + (height() / 2) - 5); - - return top - 1; - } - - void moveRight(int32_t amount) - { - left += amount; - right += amount; - } - - void moveDown(int32_t amount) - { - top += amount; - bottom += amount; - } - - void moveTo(ScreenCoordsXY coords) - { - moveRight(coords.x - left); - moveDown(coords.y - top); - } - - void moveToX(int16_t x) - { - moveRight(x - left); - } - - void moveToY(int16_t y) - { - moveDown(y - top); - } - - bool IsVisible() const - { - return !(flags & OpenRCT2::WIDGET_FLAGS::IS_HIDDEN); - } -}; - -/** - * Viewport structure - */ -struct Viewport -{ - int32_t width{}; - int32_t height{}; - ScreenCoordsXY pos{}; - ScreenCoordsXY viewPos{}; - uint32_t flags{}; - ZoomLevel zoom{}; - uint8_t rotation{}; - VisibilityCache visibility{}; - - [[nodiscard]] constexpr int32_t ViewWidth() const - { - return zoom.ApplyTo(width); - } - - [[nodiscard]] constexpr int32_t ViewHeight() const - { - return zoom.ApplyTo(height); - } - - // Use this function on coordinates that are relative to the viewport zoom i.e. a peeps x, y position after transforming - // from its x, y, z - [[nodiscard]] constexpr bool Contains(const ScreenCoordsXY& vpos) const - { - return ( - vpos.y >= viewPos.y && vpos.y < viewPos.y + ViewHeight() && vpos.x >= viewPos.x - && vpos.x < viewPos.x + ViewWidth()); - } - - // Use this function on coordinates that are relative to the screen that is been drawn i.e. the cursor position - [[nodiscard]] constexpr bool ContainsScreen(const ScreenCoordsXY& sPos) const - { - return (sPos.x >= pos.x && sPos.x < pos.x + width && sPos.y >= pos.y && sPos.y < pos.y + height); - } - - [[nodiscard]] ScreenCoordsXY ScreenToViewportCoord(const ScreenCoordsXY& screenCoord) const; - - void Invalidate() const; -}; - -struct Focus -{ - using CoordinateFocus = CoordsXYZ; - using EntityFocus = EntityId; - - ZoomLevel zoom{}; - std::variant data; - - template - constexpr explicit Focus(T newValue, ZoomLevel newZoom = {}) - { - data = newValue; - zoom = newZoom; - } - - CoordsXYZ GetPos() const; - - constexpr bool operator==(const Focus& other) const - { - if (zoom != other.zoom) + [[nodiscard]] constexpr int32_t ViewWidth() const { - return false; + return zoom.ApplyTo(width); } - return data == other.data; - } - constexpr bool operator!=(const Focus& other) const + + [[nodiscard]] constexpr int32_t ViewHeight() const + { + return zoom.ApplyTo(height); + } + + // Use this function on coordinates that are relative to the viewport zoom i.e. a peeps x, y position after transforming + // from its x, y, z + [[nodiscard]] constexpr bool Contains(const ScreenCoordsXY& vpos) const + { + return ( + vpos.y >= viewPos.y && vpos.y < viewPos.y + ViewHeight() && vpos.x >= viewPos.x + && vpos.x < viewPos.x + ViewWidth()); + } + + // Use this function on coordinates that are relative to the screen that is been drawn i.e. the cursor position + [[nodiscard]] constexpr bool ContainsScreen(const ScreenCoordsXY& sPos) const + { + return (sPos.x >= pos.x && sPos.x < pos.x + width && sPos.y >= pos.y && sPos.y < pos.y + height); + } + + [[nodiscard]] ScreenCoordsXY ScreenToViewportCoord(const ScreenCoordsXY& screenCoord) const; + + void Invalidate() const; + }; + + struct Focus { - return !(*this == other); - } -}; + using CoordinateFocus = CoordsXYZ; + using EntityFocus = EntityId; -struct WindowCloseModifier -{ - WindowIdentifier window; - CloseWindowModifier modifier; -}; + ZoomLevel zoom{}; + std::variant data; -struct WindowBase; + template + constexpr explicit Focus(T newValue, ZoomLevel newZoom = {}) + { + data = newValue; + zoom = newZoom; + } + + CoordsXYZ GetPos() const; + + constexpr bool operator==(const Focus& other) const + { + if (zoom != other.zoom) + { + return false; + } + return data == other.data; + } + constexpr bool operator!=(const Focus& other) const + { + return !(*this == other); + } + }; + + struct WindowCloseModifier + { + WindowIdentifier window; + CloseWindowModifier modifier; + }; + + struct WindowBase; #define RCT_WINDOW_RIGHT(w) ((w)->windowPos.x + (w)->width) #define RCT_WINDOW_BOTTOM(w) ((w)->windowPos.y + (w)->height) -enum WINDOW_FLAGS -{ - /* - WF_TIMEOUT_SHL = 0, - WF_TIMEOUT_MASK = 7, - WF_DRAGGING = 1 << 3, - WF_SCROLLER_UP = 1 << 4, - WF_SCROLLER_DOWN = 1 << 5, - WF_SCROLLER_MIDDLE = 1 << 6, - WF_DISABLE_VP_SCROLL = 1 << 9, - */ + enum WINDOW_FLAGS + { + /* + WF_TIMEOUT_SHL = 0, + WF_TIMEOUT_MASK = 7, + WF_DRAGGING = 1 << 3, + WF_SCROLLER_UP = 1 << 4, + WF_SCROLLER_DOWN = 1 << 5, + WF_SCROLLER_MIDDLE = 1 << 6, + WF_DISABLE_VP_SCROLL = 1 << 9, + */ - WF_STICK_TO_BACK = (1 << 0), - WF_STICK_TO_FRONT = (1 << 1), - WF_NO_SCROLLING = (1 << 2), // User is unable to scroll this viewport - WF_SCROLLING_TO_LOCATION = (1 << 3), - WF_TRANSPARENT = (1 << 4), - WF_NO_BACKGROUND = (1 << 5), // Instead of half transparency, completely remove the window background - WF_DEAD = (1u << 6), // Window is closed and will be deleted in the next update. - WF_7 = (1 << 7), - WF_RESIZABLE = (1 << 8), - WF_NO_AUTO_CLOSE = (1 << 9), // Don't auto close this window if too many windows are open - WF_10 = (1 << 10), - WF_WHITE_BORDER_ONE = (1 << 12), - WF_WHITE_BORDER_MASK = (1 << 12) | (1 << 13), + WF_STICK_TO_BACK = (1 << 0), + WF_STICK_TO_FRONT = (1 << 1), + WF_NO_SCROLLING = (1 << 2), // User is unable to scroll this viewport + WF_SCROLLING_TO_LOCATION = (1 << 3), + WF_TRANSPARENT = (1 << 4), + WF_NO_BACKGROUND = (1 << 5), // Instead of half transparency, completely remove the window background + WF_DEAD = (1u << 6), // Window is closed and will be deleted in the next update. + WF_7 = (1 << 7), + WF_RESIZABLE = (1 << 8), + WF_NO_AUTO_CLOSE = (1 << 9), // Don't auto close this window if too many windows are open + WF_10 = (1 << 10), + WF_WHITE_BORDER_ONE = (1 << 12), + WF_WHITE_BORDER_MASK = (1 << 12) | (1 << 13), - WF_NO_SNAPPING = (1 << 15), + WF_NO_SNAPPING = (1 << 15), - // Create only flags - WF_AUTO_POSITION = (1 << 16), - WF_CENTRE_SCREEN = (1 << 17), -}; + // Create only flags + WF_AUTO_POSITION = (1 << 16), + WF_CENTRE_SCREEN = (1 << 17), + }; -enum -{ - WV_PARK_AWARDS, - WV_PARK_RATING, - WV_PARK_OBJECTIVE, - WV_PARK_GUESTS, - WV_FINANCES_RESEARCH, - WV_RIDE_RESEARCH, - WV_MAZE_CONSTRUCTION, - WV_NETWORK_PASSWORD, - WV_EDITOR_BOTTOM_TOOLBAR, - WV_CHANGELOG, - WV_NEW_VERSION_INFO, - WV_FINANCE_MARKETING, - WV_CONTRIBUTORS, -}; + enum + { + WV_PARK_AWARDS, + WV_PARK_RATING, + WV_PARK_OBJECTIVE, + WV_PARK_GUESTS, + WV_FINANCES_RESEARCH, + WV_RIDE_RESEARCH, + WV_MAZE_CONSTRUCTION, + WV_NETWORK_PASSWORD, + WV_EDITOR_BOTTOM_TOOLBAR, + WV_CHANGELOG, + WV_NEW_VERSION_INFO, + WV_FINANCE_MARKETING, + WV_CONTRIBUTORS, + }; -enum WindowDetail -{ - WD_BANNER, - WD_NEW_CAMPAIGN, - WD_DEMOLISH_RIDE, - WD_REFURBISH_RIDE, - WD_SIGN, - WD_SIGN_SMALL, + enum WindowDetail + { + WD_BANNER, + WD_NEW_CAMPAIGN, + WD_DEMOLISH_RIDE, + WD_REFURBISH_RIDE, + WD_SIGN, + WD_SIGN_SMALL, - WD_PLAYER, + WD_PLAYER, - WD_VEHICLE, - WD_TRACK, + WD_VEHICLE, + WD_TRACK, - WD_NULL = 255, -}; + WD_NULL = 255, + }; +} // namespace OpenRCT2 #define validate_global_widx(wc, widx) \ static_assert(widx == wc##__##widx, "Global WIDX of " #widx " doesn't match actual value.") @@ -344,29 +243,29 @@ constexpr int32_t WC_TILE_INSPECTOR__WIDX_SPINNER_X_DECREASE = 7; constexpr int32_t WC_TILE_INSPECTOR__WIDX_SPINNER_Y_INCREASE = 10; constexpr int32_t WC_TILE_INSPECTOR__WIDX_SPINNER_Y_DECREASE = 11; constexpr int32_t WC_TILE_INSPECTOR__TILE_INSPECTOR_PAGE_SURFACE = EnumValue(TileInspectorPage::Surface); -constexpr int32_t WC_TILE_INSPECTOR__WIDX_SURFACE_SPINNER_HEIGHT_INCREASE = 27; -constexpr int32_t WC_TILE_INSPECTOR__WIDX_SURFACE_SPINNER_HEIGHT_DECREASE = 28; +constexpr int32_t WC_TILE_INSPECTOR__WIDX_SURFACE_SPINNER_HEIGHT_INCREASE = 29; +constexpr int32_t WC_TILE_INSPECTOR__WIDX_SURFACE_SPINNER_HEIGHT_DECREASE = 30; constexpr int32_t WC_TILE_INSPECTOR__TILE_INSPECTOR_PAGE_PATH = EnumValue(TileInspectorPage::Path); -constexpr int32_t WC_TILE_INSPECTOR__WIDX_PATH_SPINNER_HEIGHT_INCREASE = 27; -constexpr int32_t WC_TILE_INSPECTOR__WIDX_PATH_SPINNER_HEIGHT_DECREASE = 28; +constexpr int32_t WC_TILE_INSPECTOR__WIDX_PATH_SPINNER_HEIGHT_INCREASE = 29; +constexpr int32_t WC_TILE_INSPECTOR__WIDX_PATH_SPINNER_HEIGHT_DECREASE = 30; constexpr int32_t WC_TILE_INSPECTOR__TILE_INSPECTOR_PAGE_TRACK = EnumValue(TileInspectorPage::Track); -constexpr int32_t WC_TILE_INSPECTOR__WIDX_TRACK_SPINNER_HEIGHT_INCREASE = 28; -constexpr int32_t WC_TILE_INSPECTOR__WIDX_TRACK_SPINNER_HEIGHT_DECREASE = 29; +constexpr int32_t WC_TILE_INSPECTOR__WIDX_TRACK_SPINNER_HEIGHT_INCREASE = 30; +constexpr int32_t WC_TILE_INSPECTOR__WIDX_TRACK_SPINNER_HEIGHT_DECREASE = 31; constexpr int32_t WC_TILE_INSPECTOR__TILE_INSPECTOR_PAGE_SCENERY = EnumValue(TileInspectorPage::Scenery); -constexpr int32_t WC_TILE_INSPECTOR__WIDX_SCENERY_SPINNER_HEIGHT_INCREASE = 27; -constexpr int32_t WC_TILE_INSPECTOR__WIDX_SCENERY_SPINNER_HEIGHT_DECREASE = 28; +constexpr int32_t WC_TILE_INSPECTOR__WIDX_SCENERY_SPINNER_HEIGHT_INCREASE = 29; +constexpr int32_t WC_TILE_INSPECTOR__WIDX_SCENERY_SPINNER_HEIGHT_DECREASE = 30; constexpr int32_t WC_TILE_INSPECTOR__TILE_INSPECTOR_PAGE_ENTRANCE = EnumValue(TileInspectorPage::Entrance); -constexpr int32_t WC_TILE_INSPECTOR__WIDX_ENTRANCE_SPINNER_HEIGHT_INCREASE = 27; -constexpr int32_t WC_TILE_INSPECTOR__WIDX_ENTRANCE_SPINNER_HEIGHT_DECREASE = 28; +constexpr int32_t WC_TILE_INSPECTOR__WIDX_ENTRANCE_SPINNER_HEIGHT_INCREASE = 29; +constexpr int32_t WC_TILE_INSPECTOR__WIDX_ENTRANCE_SPINNER_HEIGHT_DECREASE = 30; constexpr int32_t WC_TILE_INSPECTOR__TILE_INSPECTOR_PAGE_WALL = EnumValue(TileInspectorPage::Wall); -constexpr int32_t WC_TILE_INSPECTOR__WIDX_WALL_SPINNER_HEIGHT_INCREASE = 27; -constexpr int32_t WC_TILE_INSPECTOR__WIDX_WALL_SPINNER_HEIGHT_DECREASE = 28; +constexpr int32_t WC_TILE_INSPECTOR__WIDX_WALL_SPINNER_HEIGHT_INCREASE = 29; +constexpr int32_t WC_TILE_INSPECTOR__WIDX_WALL_SPINNER_HEIGHT_DECREASE = 30; constexpr int32_t WC_TILE_INSPECTOR__TILE_INSPECTOR_PAGE_LARGE_SCENERY = EnumValue(TileInspectorPage::LargeScenery); -constexpr int32_t WC_TILE_INSPECTOR__WIDX_LARGE_SCENERY_SPINNER_HEIGHT_INCREASE = 27; -constexpr int32_t WC_TILE_INSPECTOR__WIDX_LARGE_SCENERY_SPINNER_HEIGHT_DECREASE = 28; +constexpr int32_t WC_TILE_INSPECTOR__WIDX_LARGE_SCENERY_SPINNER_HEIGHT_INCREASE = 29; +constexpr int32_t WC_TILE_INSPECTOR__WIDX_LARGE_SCENERY_SPINNER_HEIGHT_DECREASE = 30; constexpr int32_t WC_TILE_INSPECTOR__TILE_INSPECTOR_PAGE_BANNER = EnumValue(TileInspectorPage::Banner); -constexpr int32_t WC_TILE_INSPECTOR__WIDX_BANNER_SPINNER_HEIGHT_INCREASE = 27; -constexpr int32_t WC_TILE_INSPECTOR__WIDX_BANNER_SPINNER_HEIGHT_DECREASE = 28; +constexpr int32_t WC_TILE_INSPECTOR__WIDX_BANNER_SPINNER_HEIGHT_INCREASE = 29; +constexpr int32_t WC_TILE_INSPECTOR__WIDX_BANNER_SPINNER_HEIGHT_DECREASE = 30; enum class PromptMode : uint8_t { @@ -444,105 +343,109 @@ enum class Tool Bulldozer = 27, }; -struct WidgetRef +namespace OpenRCT2 { - WindowClass window_classification; - rct_windownumber window_number; - WidgetIndex widget_index; -}; + struct WidgetRef + { + WindowClass window_classification; + rct_windownumber window_number; + WidgetIndex widget_index; + }; -extern Tool gCurrentToolId; -extern WidgetRef gCurrentToolWidget; + extern Tool gCurrentToolId; + extern WidgetRef gCurrentToolWidget; -using modal_callback = void (*)(int32_t result); -using CloseCallback = void (*)(); + using modal_callback = void (*)(int32_t result); + using CloseCallback = void (*)(); -constexpr int8_t kWindowLimitMin = 4; -constexpr int8_t kWindowLimitMax = 64; -constexpr int8_t kWindowLimitReserved = 4; // Used to reserve room for the main viewport, toolbars, etc. + constexpr int8_t kWindowLimitMin = 4; + constexpr int8_t kWindowLimitMax = 64; + constexpr int8_t kWindowLimitReserved = 4; // Used to reserve room for the main viewport, toolbars, etc. -extern WindowBase* gWindowAudioExclusive; + extern WindowBase* gWindowAudioExclusive; -extern uint32_t gWindowUpdateTicks; + extern uint32_t gWindowUpdateTicks; -extern colour_t gCurrentWindowColours[3]; + extern colour_t gCurrentWindowColours[3]; -std::list>::iterator WindowGetIterator(const WindowBase* w); -void WindowVisitEach(std::function func); + std::list>::iterator WindowGetIterator(const WindowBase* w); + void WindowVisitEach(std::function func); -void WindowSetFlagForAllViewports(uint32_t viewportFlag, bool enabled); + void WindowSetFlagForAllViewports(uint32_t viewportFlag, bool enabled); -void WindowDispatchUpdateAll(); -void WindowUpdateAllViewports(); -void WindowUpdateAll(); -void WindowNotifyLanguageChange(); + void WindowDispatchUpdateAll(); + void WindowUpdateAllViewports(); + void WindowUpdateAll(); + void WindowNotifyLanguageChange(); -void WindowSetWindowLimit(int32_t value); + void WindowSetWindowLimit(int32_t value); -WindowBase* WindowBringToFront(WindowBase& w); -WindowBase* WindowBringToFrontByClass(WindowClass cls); -WindowBase* WindowBringToFrontByClassWithFlags(WindowClass cls, uint16_t flags); -WindowBase* WindowBringToFrontByNumber(WindowClass cls, rct_windownumber number); + WindowBase* WindowBringToFront(WindowBase& w); + WindowBase* WindowBringToFrontByClass(WindowClass cls); + WindowBase* WindowBringToFrontByClassWithFlags(WindowClass cls, uint16_t flags); + WindowBase* WindowBringToFrontByNumber(WindowClass cls, rct_windownumber number); -void WindowClose(WindowBase& window); -void WindowCloseByClass(WindowClass cls); -void WindowCloseByNumber(WindowClass cls, rct_windownumber number); -void WindowCloseByNumber(WindowClass cls, EntityId number); -void WindowCloseTop(); -void WindowCloseAll(); -void WindowCloseAllExceptClass(WindowClass cls); -void WindowCloseAllExceptFlags(uint16_t flags); -void WindowCloseAllExceptNumberAndClass(rct_windownumber number, WindowClass cls); -void WindowInvalidateByClass(WindowClass cls); -void WindowInvalidateByNumber(WindowClass cls, rct_windownumber number); -void WindowInvalidateByNumber(WindowClass cls, EntityId id); -void WindowInvalidateAll(); -void WidgetInvalidate(WindowBase& w, WidgetIndex widgetIndex); -void WidgetInvalidateByClass(WindowClass cls, WidgetIndex widgetIndex); -void WidgetInvalidateByNumber(WindowClass cls, rct_windownumber number, WidgetIndex widgetIndex); + void WindowClose(WindowBase& window); + void WindowCloseByClass(WindowClass cls); + void WindowCloseByNumber(WindowClass cls, rct_windownumber number); + void WindowCloseByNumber(WindowClass cls, EntityId number); + void WindowCloseTop(); + void WindowCloseAll(); + void WindowCloseAllExceptClass(WindowClass cls); + void WindowCloseAllExceptFlags(uint16_t flags); + void WindowCloseAllExceptNumberAndClass(rct_windownumber number, WindowClass cls); + void WindowInvalidateByClass(WindowClass cls); + void WindowInvalidateByNumber(WindowClass cls, rct_windownumber number); + void WindowInvalidateByNumber(WindowClass cls, EntityId id); + void WindowInvalidateAll(); + void WidgetInvalidate(WindowBase& w, WidgetIndex widgetIndex); + void WidgetInvalidateByClass(WindowClass cls, WidgetIndex widgetIndex); + void WidgetInvalidateByNumber(WindowClass cls, rct_windownumber number, WidgetIndex widgetIndex); -int32_t WindowGetScrollDataIndex(const WindowBase& w, WidgetIndex widget_index); + int32_t WindowGetScrollDataIndex(const WindowBase& w, WidgetIndex widget_index); -void WindowPushOthersRight(WindowBase& w); -void WindowPushOthersBelow(WindowBase& w1); + void WindowPushOthersRight(WindowBase& w); + void WindowPushOthersBelow(WindowBase& w1); -WindowBase* WindowGetMain(); + WindowBase* WindowGetMain(); -void WindowScrollToLocation(WindowBase& w, const CoordsXYZ& coords); -void WindowViewportGetMapCoordsByCursor( - const WindowBase& w, int32_t* map_x, int32_t* map_y, int32_t* offset_x, int32_t* offset_y); -void WindowViewportCentreTileAroundCursor(WindowBase& w, int32_t map_x, int32_t map_y, int32_t offset_x, int32_t offset_y); -void WindowCheckAllValidZoom(); -void WindowZoomSet(WindowBase& w, ZoomLevel zoomLevel, bool atCursor); + void WindowScrollToLocation(WindowBase& w, const CoordsXYZ& coords); + void WindowViewportGetMapCoordsByCursor( + const WindowBase& w, int32_t* map_x, int32_t* map_y, int32_t* offset_x, int32_t* offset_y); + void WindowViewportCentreTileAroundCursor(WindowBase& w, int32_t map_x, int32_t map_y, int32_t offset_x, int32_t offset_y); + void WindowCheckAllValidZoom(); + void WindowZoomSet(WindowBase& w, ZoomLevel zoomLevel, bool atCursor); -void WindowDrawAll(DrawPixelInfo& dpi, int32_t left, int32_t top, int32_t right, int32_t bottom); -void WindowDraw(DrawPixelInfo& dpi, WindowBase& w, int32_t left, int32_t top, int32_t right, int32_t bottom); + void WindowDrawAll(DrawPixelInfo& dpi, int32_t left, int32_t top, int32_t right, int32_t bottom); + void WindowDraw(DrawPixelInfo& dpi, WindowBase& w, int32_t left, int32_t top, int32_t right, int32_t bottom); -bool isToolActive(WindowClass cls); -bool isToolActive(WindowClass cls, rct_windownumber number); -bool isToolActive(WindowClass cls, WidgetIndex widgetIndex); -bool isToolActive(WindowClass cls, WidgetIndex widgetIndex, rct_windownumber number); -bool isToolActive(const WindowBase& w, WidgetIndex widgetIndex); -bool ToolSet(const WindowBase& w, WidgetIndex widgetIndex, Tool tool); -void ToolCancel(); + bool isToolActive(WindowClass cls); + bool isToolActive(WindowClass cls, rct_windownumber number); + bool isToolActive(WindowClass cls, WidgetIndex widgetIndex); + bool isToolActive(WindowClass cls, WidgetIndex widgetIndex, rct_windownumber number); + bool isToolActive(const WindowBase& w, WidgetIndex widgetIndex); + bool ToolSet(const WindowBase& w, WidgetIndex widgetIndex, Tool tool); + void ToolCancel(); -void WindowCloseConstructionWindows(); + void WindowCloseConstructionWindows(); -void WindowUpdateViewportRideMusic(); + void WindowUpdateViewportRideMusic(); -Viewport* WindowGetViewport(WindowBase* window); + Viewport* WindowGetViewport(WindowBase* window); -// Open window functions -void WindowResizeGui(int32_t width, int32_t height); -void WindowResizeGuiScenarioEditor(int32_t width, int32_t height); + // Open window functions + void WindowResizeGui(int32_t width, int32_t height); + void WindowResizeGuiScenarioEditor(int32_t width, int32_t height); -void TextinputCancel(); + void TextinputCancel(); -bool WindowIsVisible(WindowBase& w); + bool WindowIsVisible(WindowBase& w); -Viewport* WindowGetPreviousViewport(Viewport* current); -void WindowResetVisibilities(); -void WindowInitAll(); + Viewport* WindowGetPreviousViewport(Viewport* current); + void WindowResetVisibilities(); + void WindowInitAll(); -void WindowFollowSprite(WindowBase& w, EntityId spriteIndex); -void WindowUnfollowSprite(WindowBase& w); + void WindowFollowSprite(WindowBase& w, EntityId spriteIndex); + void WindowUnfollowSprite(WindowBase& w); + +} // namespace OpenRCT2 diff --git a/src/openrct2/interface/Window_internal.cpp b/src/openrct2/interface/Window_internal.cpp index fce2f83985..bded773da8 100644 --- a/src/openrct2/interface/Window_internal.cpp +++ b/src/openrct2/interface/Window_internal.cpp @@ -5,27 +5,36 @@ #include "Cursors.h" #include "Viewport.h" -void WindowBase::SetLocation(const CoordsXYZ& coords) +namespace OpenRCT2 { - WindowScrollToLocation(*this, coords); - flags &= ~WF_SCROLLING_TO_LOCATION; -} + void WindowBase::SetLocation(const CoordsXYZ& coords) + { + WindowScrollToLocation(*this, coords); + flags &= ~WF_SCROLLING_TO_LOCATION; + } -void WindowBase::Invalidate() -{ - GfxSetDirtyBlocks({ windowPos, windowPos + ScreenCoordsXY{ width, height } }); -} + void WindowBase::Invalidate() + { + GfxSetDirtyBlocks({ windowPos, windowPos + ScreenCoordsXY{ width, height } }); + } -void WindowBase::RemoveViewport() -{ - if (viewport == nullptr) - return; + void WindowBase::RemoveViewport() + { + if (viewport == nullptr) + return; - ViewportRemove(viewport); - viewport = nullptr; -} + ViewportRemove(viewport); + viewport = nullptr; + } -CursorID WindowBase::OnCursor(WidgetIndex, const ScreenCoordsXY&, CursorID) -{ - return CursorID::Arrow; -} + void WindowBase::SetWidgets(const std::span newWidgets) + { + widgets.clear(); + widgets.insert(widgets.end(), newWidgets.begin(), newWidgets.end()); + } + + CursorID WindowBase::OnCursor(WidgetIndex, const ScreenCoordsXY&, CursorID) + { + return CursorID::Arrow; + } +} // namespace OpenRCT2 diff --git a/src/openrct2/interface/Window_internal.h b/src/openrct2/interface/Window_internal.h index 83e4305012..471989b5eb 100644 --- a/src/openrct2/interface/Window_internal.h +++ b/src/openrct2/interface/Window_internal.h @@ -9,12 +9,15 @@ #pragma once +#include "../localisation/Formatter.h" #include "Colour.h" #include "ScrollArea.h" #include "Window.h" #include #include +#include +#include enum class TileInspectorPage : int16_t; @@ -27,154 +30,158 @@ struct RCTObjectEntry; #pragma GCC diagnostic ignored "-Wsuggest-final-types" #endif -/** - * Window structure - * size: 0x4C0 - */ -struct WindowBase +namespace OpenRCT2 { - Viewport* viewport{}; - uint64_t disabled_widgets{}; - uint64_t pressed_widgets{}; - uint64_t hold_down_widgets{}; - Widget* widgets{}; - ScreenCoordsXY windowPos; - int16_t width{}; - int16_t height{}; - int16_t min_width{}; - int16_t max_width{}; - int16_t min_height{}; - int16_t max_height{}; - union + /** + * Window structure + * size: 0x4C0 + */ + struct WindowBase { - rct_windownumber number{}; - RideId rideId; + Viewport* viewport{}; + uint64_t disabled_widgets{}; + uint64_t pressed_widgets{}; + uint64_t hold_down_widgets{}; + std::vector widgets{}; + ScreenCoordsXY windowPos; + int16_t width{}; + int16_t height{}; + int16_t min_width{}; + int16_t max_width{}; + int16_t min_height{}; + int16_t max_height{}; + union + { + rct_windownumber number{}; + RideId rideId; + }; + uint16_t flags{}; + OpenRCT2::ScrollArea scrolls[3]; + uint16_t no_list_items{}; // 0 for no items + int16_t selected_list_item{}; // -1 for none selected + std::optional focus; + union + { + int16_t page{}; + TileInspectorPage tileInspectorPage; + }; + uint16_t frame_no{}; // updated every tic for motion in windows sprites + uint16_t list_information_type{}; // 0 for none + int16_t picked_peep_frame; // Animation frame of picked peep in staff window and guest window + int16_t selected_tab{}; + EntityId viewport_target_sprite{ EntityId::GetNull() }; + ScreenCoordsXY savedViewPos{}; + WindowClass classification{}; + ColourWithFlags colours[6]{}; + VisibilityCache visibility{}; + EntityId viewport_smart_follow_sprite{ EntityId::GetNull() }; // Handles setting viewport target sprite etc + + void SetLocation(const CoordsXYZ& coords); + void Invalidate(); + void RemoveViewport(); + void SetWidgets(const std::span newWidgets); + + WindowBase() = default; + WindowBase(WindowBase&) = delete; + virtual ~WindowBase() = default; + + WindowBase& operator=(const WindowBase&) = delete; + + // Events + virtual void OnOpen() + { + } + virtual bool CanClose() + { + return true; + } + virtual void OnClose() + { + } + virtual void OnResize() + { + } + virtual void OnUpdate() + { + } + virtual void OnPeriodicUpdate() + { + } + virtual void OnPrepareDraw() + { + } + virtual void OnDraw(DrawPixelInfo& dpi) + { + } + virtual void OnDrawWidget(WidgetIndex widgetIndex, DrawPixelInfo& dpi) + { + } + virtual OpenRCT2String OnTooltip(WidgetIndex widgetIndex, StringId fallback) + { + return { fallback, {} }; + } + virtual void OnMouseDown(WidgetIndex widgetIndex) + { + } + virtual void OnMouseUp(WidgetIndex widgetIndex) + { + } + virtual void OnDropdown(WidgetIndex widgetIndex, int32_t selectedIndex) + { + } + virtual void OnTextInput(WidgetIndex widgetIndex, std::string_view text) + { + } + virtual ScreenSize OnScrollGetSize(int32_t scrollIndex) + { + return {}; + } + virtual void OnScrollSelect(int32_t scrollIndex, int32_t scrollAreaType) + { + } + virtual void OnScrollMouseDrag(int32_t scrollIndex, const ScreenCoordsXY& screenCoords) + { + } + virtual void OnScrollMouseOver(int32_t scrollIndex, const ScreenCoordsXY& screenCoords) + { + } + virtual void OnScrollMouseDown(int32_t scrollIndex, const ScreenCoordsXY& screenCoords) + { + } + virtual void OnScrollDraw(int32_t scrollIndex, DrawPixelInfo& dpi) + { + } + virtual void OnToolUpdate(WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords) + { + } + virtual void OnToolDown(WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords) + { + } + virtual void OnToolDrag(WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords) + { + } + virtual void OnToolUp(WidgetIndex widgetIndex, const ScreenCoordsXY&) + { + } + virtual void OnToolAbort(WidgetIndex widgetIndex) + { + } + virtual void OnViewportRotate() + { + } + virtual void OnMoved(const ScreenCoordsXY&) + { + } + virtual CursorID OnCursor(WidgetIndex, const ScreenCoordsXY&, CursorID); + virtual void OnLanguageChange() + { + } }; - uint16_t flags{}; - OpenRCT2::ScrollArea scrolls[3]; - uint16_t no_list_items{}; // 0 for no items - int16_t selected_list_item{}; // -1 for none selected - std::optional focus; - union - { - int16_t page{}; - TileInspectorPage tileInspectorPage; - }; - uint16_t frame_no{}; // updated every tic for motion in windows sprites - uint16_t list_information_type{}; // 0 for none - int16_t picked_peep_frame; // Animation frame of picked peep in staff window and guest window - int16_t selected_tab{}; - EntityId viewport_target_sprite{ EntityId::GetNull() }; - ScreenCoordsXY savedViewPos{}; - WindowClass classification{}; - ColourWithFlags colours[6]{}; - VisibilityCache visibility{}; - EntityId viewport_smart_follow_sprite{ EntityId::GetNull() }; // Handles setting viewport target sprite etc - - void SetLocation(const CoordsXYZ& coords); - void Invalidate(); - void RemoveViewport(); - - WindowBase() = default; - WindowBase(WindowBase&) = delete; - virtual ~WindowBase() = default; - - WindowBase& operator=(const WindowBase&) = delete; - - // Events - virtual void OnOpen() - { - } - virtual bool CanClose() - { - return true; - } - virtual void OnClose() - { - } - virtual void OnResize() - { - } - virtual void OnUpdate() - { - } - virtual void OnPeriodicUpdate() - { - } - virtual void OnPrepareDraw() - { - } - virtual void OnDraw(DrawPixelInfo& dpi) - { - } - virtual void OnDrawWidget(WidgetIndex widgetIndex, DrawPixelInfo& dpi) - { - } - virtual OpenRCT2String OnTooltip(WidgetIndex widgetIndex, StringId fallback) - { - return { fallback, {} }; - } - virtual void OnMouseDown(WidgetIndex widgetIndex) - { - } - virtual void OnMouseUp(WidgetIndex widgetIndex) - { - } - virtual void OnDropdown(WidgetIndex widgetIndex, int32_t selectedIndex) - { - } - virtual void OnTextInput(WidgetIndex widgetIndex, std::string_view text) - { - } - virtual ScreenSize OnScrollGetSize(int32_t scrollIndex) - { - return {}; - } - virtual void OnScrollSelect(int32_t scrollIndex, int32_t scrollAreaType) - { - } - virtual void OnScrollMouseDrag(int32_t scrollIndex, const ScreenCoordsXY& screenCoords) - { - } - virtual void OnScrollMouseOver(int32_t scrollIndex, const ScreenCoordsXY& screenCoords) - { - } - virtual void OnScrollMouseDown(int32_t scrollIndex, const ScreenCoordsXY& screenCoords) - { - } - virtual void OnScrollDraw(int32_t scrollIndex, DrawPixelInfo& dpi) - { - } - virtual void OnToolUpdate(WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords) - { - } - virtual void OnToolDown(WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords) - { - } - virtual void OnToolDrag(WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords) - { - } - virtual void OnToolUp(WidgetIndex widgetIndex, const ScreenCoordsXY&) - { - } - virtual void OnToolAbort(WidgetIndex widgetIndex) - { - } - virtual void OnViewportRotate() - { - } - virtual void OnMoved(const ScreenCoordsXY&) - { - } - virtual CursorID OnCursor(WidgetIndex, const ScreenCoordsXY&, CursorID); - virtual void OnLanguageChange() - { - } -}; #ifdef __WARN_SUGGEST_FINAL_METHODS__ #pragma GCC diagnostic pop #endif -// rct2: 0x01420078 -extern std::list> g_window_list; + // rct2: 0x01420078 + extern std::list> g_window_list; +} // namespace OpenRCT2 diff --git a/src/openrct2/localisation/StringIds.h b/src/openrct2/localisation/StringIds.h index 181130dcad..eca57ead66 100644 --- a/src/openrct2/localisation/StringIds.h +++ b/src/openrct2/localisation/StringIds.h @@ -1187,7 +1187,7 @@ enum : StringId STR_CANT_REPAINT_THIS = 3103, STR_ERR_UNABLE_TO_BUILD_THIS_ON_SLOPE = 3133, STR_CABLE_LIFT_UNABLE_TO_WORK_IN_THIS_OPERATING_MODE = 3139, - STR_CABLE_LIFT_HILL_MUST_START_IMMEDIATELY_AFTER_STATION = 3140, + STR_CABLE_LIFT_HILL_MUST_START_IMMEDIATELY_AFTER_STATION_OR_BLOCK_BRAKE = 6729, STR_MULTICIRCUIT_NOT_POSSIBLE_WITH_CABLE_LIFT_HILL = 3141, STR_SELECT_NUMBER_OF_CIRCUITS_TIP = 3160, @@ -1721,6 +1721,9 @@ enum : StringId STR_AT_LEAST_ONE_ENTERTAINER_PEEP_ANIMATIONS_OBJECT_MUST_BE_SELECTED = 6723, STR_OBJECT_SELECTION_SCENARIO_TEXTS = 6724, + STR_DIVE_LOOP_LEFT = 6727, + STR_DIVE_LOOP_RIGHT = 6728, + // Have to include resource strings (from scenarios and objects) for the time being now that language is partially working /* MAX_STR_COUNT = 32768 */ // MAX_STR_COUNT - upper limit for number of strings, not the current count strings }; diff --git a/src/openrct2/network/NetworkBase.cpp b/src/openrct2/network/NetworkBase.cpp index 02bc11ad11..0194e5ab8c 100644 --- a/src/openrct2/network/NetworkBase.cpp +++ b/src/openrct2/network/NetworkBase.cpp @@ -50,7 +50,7 @@ using namespace OpenRCT2; // It is used for making sure only compatible builds get connected, even within // single OpenRCT2 version. -constexpr uint8_t kNetworkStreamVersion = 1; +constexpr uint8_t kNetworkStreamVersion = 4; const std::string kNetworkStreamID = std::string(OPENRCT2_VERSION) + "-" + std::to_string(kNetworkStreamVersion); diff --git a/src/openrct2/network/NetworkPlayer.cpp b/src/openrct2/network/NetworkPlayer.cpp index ab381be97c..4eb0eeca31 100644 --- a/src/openrct2/network/NetworkPlayer.cpp +++ b/src/openrct2/network/NetworkPlayer.cpp @@ -39,13 +39,13 @@ void NetworkPlayer::Write(NetworkPacket& packet) void NetworkPlayer::IncrementNumCommands() { CommandsRan++; - WindowInvalidateByNumber(WindowClass::Player, Id); + OpenRCT2::WindowInvalidateByNumber(WindowClass::Player, Id); } void NetworkPlayer::AddMoneySpent(money64 cost) { MoneySpent += cost; - WindowInvalidateByNumber(WindowClass::Player, Id); + OpenRCT2::WindowInvalidateByNumber(WindowClass::Player, Id); } #endif diff --git a/src/openrct2/object/RideObject.cpp b/src/openrct2/object/RideObject.cpp index 98855a6cba..3c2fc8eb21 100644 --- a/src/openrct2/object/RideObject.cpp +++ b/src/openrct2/object/RideObject.cpp @@ -55,7 +55,7 @@ using namespace OpenRCT2::Numerics; * - curvedLiftHillUp and curvedLiftHillDown are 1 (normally would be combined, but aren't due to RCT2) */ static const uint8_t SpriteGroupMultiplier[EnumValue(SpriteGroupType::Count)] = { - 1, 2, 2, 2, 2, 2, 2, 10, 1, 2, 2, 2, 2, 2, 2, 2, 6, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 12, 4, 4, 4, 4, 4, 20, 3, 1, 1, + 1, 2, 2, 2, 2, 2, 2, 10, 1, 2, 2, 2, 2, 2, 2, 2, 6, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 12, 4, 4, 4, 4, 4, 4, 4, 4, 20, 3, 1, 1, }; static_assert(std::size(SpriteGroupMultiplier) == EnumValue(SpriteGroupType::Count)); diff --git a/src/openrct2/paint/Paint.Entity.cpp b/src/openrct2/paint/Paint.Entity.cpp index d0ef7259c7..7da6bc92d3 100644 --- a/src/openrct2/paint/Paint.Entity.cpp +++ b/src/openrct2/paint/Paint.Entity.cpp @@ -32,6 +32,7 @@ #include +using namespace OpenRCT2; using namespace OpenRCT2::Drawing; /** diff --git a/src/openrct2/paint/track/coaster/CorkscrewRollerCoaster.cpp b/src/openrct2/paint/track/coaster/CorkscrewRollerCoaster.cpp index 82dc2b7f63..0fcb05bf18 100644 --- a/src/openrct2/paint/track/coaster/CorkscrewRollerCoaster.cpp +++ b/src/openrct2/paint/track/coaster/CorkscrewRollerCoaster.cpp @@ -19382,6 +19382,1402 @@ static void CorkscrewRCTrackRightLargeZeroGRollDown( session, ride, 3 - trackSequence, (direction + 2) & 3, height, trackElement, supportType); } +static void CorkscrewRCTrackDiagFlatTo60DegUpLongBase( + PaintSession& session, const Ride& ride, uint8_t trackSequence, uint8_t direction, int32_t height, + const TrackElement& trackElement, SupportType supportType) +{ + switch (trackSequence) + { + case 0: + switch (direction) + { + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 9)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::centre, PaintSegment::topRightSide, PaintSegment::bottomRightSide, + PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 32); + break; + case 1: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 0)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 48); + break; + case 2: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 6)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 48); + break; + case 3: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 0, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 3)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 0, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 0, height + 0, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 10)), + { -16, -16, height }, { { -20, -20, height + 8 }, { 24, 24, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 0, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, PaintSegment::centre, + PaintSegment::topRightSide, PaintSegment::bottomRightSide, PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 64); + break; + case 4: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 1)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 72); + break; + case 5: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 7)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 72); + break; + case 6: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 13, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 4)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 13, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 13, height + 0, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 11)), + { -16, -16, height }, { { -16, -16, height + 32 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 13, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, PaintSegment::centre, + PaintSegment::topRightSide, PaintSegment::bottomRightSide, PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 96); + break; + case 7: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 2)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 120); + break; + case 8: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 8)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 120); + break; + case 9: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 21, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 5)), + { -16, -16, height }, { { -16, -16, height + 80 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 21, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 21, height + 0, session.SupportColours); + break; + case 3: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 21, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, + PaintSegment::centre), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 136); + break; + } +} + +static void CorkscrewRCTrackDiag60DegUpToFlatLongBase( + PaintSession& session, const Ride& ride, uint8_t trackSequence, uint8_t direction, int32_t height, + const TrackElement& trackElement, SupportType supportType) +{ + switch (trackSequence) + { + case 0: + switch (direction) + { + case 3: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 21)), + { -16, -16, height }, { { -8, -8, height + 0 }, { 16, 16, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::centre, PaintSegment::topRightSide, PaintSegment::bottomRightSide, + PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 96); + break; + case 1: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 12)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 104); + break; + case 2: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 18)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 104); + break; + case 3: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 30, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 15)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 30, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 30, height + 0, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 22)), + { -16, -16, height }, { { -8, -8, height + 56 }, { 16, 16, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 30, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, PaintSegment::centre, + PaintSegment::topRightSide, PaintSegment::bottomRightSide, PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 112); + break; + case 4: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 13)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 64); + break; + case 5: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 19)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 64); + break; + case 6: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 12, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 16)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 12, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 12, height + 0, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 23)), + { -16, -16, height }, { { -16, -16, height + 24 }, { 24, 24, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 12, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, PaintSegment::centre, + PaintSegment::topRightSide, PaintSegment::bottomRightSide, PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 40); + break; + case 7: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 14)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 40); + break; + case 8: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 20)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 40); + break; + case 9: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 5, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 17)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 5, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 5, height + 0, session.SupportColours); + break; + case 3: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 5, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, + PaintSegment::centre), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 40); + break; + } +} + +static void CorkscrewRCTrackDiagFlatTo60DegDownLongBase( + PaintSession& session, const Ride& ride, uint8_t trackSequence, uint8_t direction, int32_t height, + const TrackElement& trackElement, SupportType supportType) +{ + switch (trackSequence) + { + case 0: + switch (direction) + { + case 3: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 17)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::centre, PaintSegment::topRightSide, PaintSegment::bottomRightSide, + PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 40); + break; + case 1: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 20)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 40); + break; + case 2: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 14)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 40); + break; + case 3: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 26, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 23)), + { -16, -16, height }, { { -16, -16, height + 24 }, { 24, 24, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 26, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 26, height + 0, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 16)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 26, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, PaintSegment::centre, + PaintSegment::topRightSide, PaintSegment::bottomRightSide, PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 40); + break; + case 4: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 19)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 64); + break; + case 5: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 13)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 64); + break; + case 6: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 60, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 22)), + { -16, -16, height }, { { -8, -8, height + 56 }, { 16, 16, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 60, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 60, height + 0, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 15)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 60, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, PaintSegment::centre, + PaintSegment::topRightSide, PaintSegment::bottomRightSide, PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 112); + break; + case 7: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 18)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 104); + break; + case 8: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 12)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 104); + break; + case 9: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 16, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 21)), + { -16, -16, height }, { { -8, -8, height + 0 }, { 16, 16, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 16, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 16, height + 0, session.SupportColours); + break; + case 3: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 16, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, + PaintSegment::centre), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 96); + break; + } +} + +static void CorkscrewRCTrackDiag60DegDownToFlatLongBase( + PaintSession& session, const Ride& ride, uint8_t trackSequence, uint8_t direction, int32_t height, + const TrackElement& trackElement, SupportType supportType) +{ + switch (trackSequence) + { + case 0: + switch (direction) + { + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 5)), + { -16, -16, height }, { { -16, -16, height + 80 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::centre, PaintSegment::topRightSide, PaintSegment::bottomRightSide, + PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 136); + break; + case 1: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 8)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 120); + break; + case 2: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 2)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 120); + break; + case 3: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 40, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 11)), + { -16, -16, height }, { { -16, -16, height + 32 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 40, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 40, height + 0, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 4)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 40, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, PaintSegment::centre, + PaintSegment::topRightSide, PaintSegment::bottomRightSide, PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 96); + break; + case 4: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 7)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 72); + break; + case 5: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 1)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 72); + break; + case 6: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 14, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 10)), + { -16, -16, height }, { { -8, -8, height + 8 }, { 24, 24, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 14, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 14, height + 0, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 3)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 14, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, PaintSegment::centre, + PaintSegment::topRightSide, PaintSegment::bottomRightSide, PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 64); + break; + case 7: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 6)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 48); + break; + case 8: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 0)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 48); + break; + case 9: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 0, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 9)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 0, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 0, height + 0, session.SupportColours); + break; + case 3: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 0, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, + PaintSegment::centre), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 32); + break; + } +} + +static void CorkscrewRCTrackLeftEighthDiveLoopUpToOrthogonal( + PaintSession& session, const Ride& ride, uint8_t trackSequence, uint8_t direction, int32_t height, + const TrackElement& trackElement, SupportType supportType) +{ + switch (trackSequence) + { + case 0: + switch (direction) + { + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_DIVE_LOOP + 4)), + { -16, -16, height }, { { 0, 0, height + 48 }, { 32, 32, 1 } }); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_DIVE_LOOP + 12)), + { -16, -16, height }, { { 0, 0, height + -8 }, { 32, 32, 1 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::centre, PaintSegment::topRightSide, PaintSegment::bottomRightSide, + PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 96); + break; + case 1: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_DIVE_LOOP + 0)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 120); + break; + case 2: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_DIVE_LOOP + 8)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 120); + break; + case 3: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_DIVE_LOOP + 1)), + { -16, -16, height }, { { 0, 31, height + 0 }, { 32, 1, 64 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 0, height + 6, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_DIVE_LOOP + 5)), + { -16, -16, height }, { { 0, 31, height + 0 }, { 32, 1, 64 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 0, height + 6, session.SupportColours); + break; + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_DIVE_LOOP + 9)), + { -16, -16, height }, { { 2, 2, height + 6 }, { 28, 28, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 0, height + 6, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_DIVE_LOOP + 13)), + { -16, -16, height }, { { 2, 2, height + 12 }, { 28, 28, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 0, height + 6, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::topCorner, + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 112); + break; + case 4: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_DIVE_LOOP + 2)), + { -16, -16, height }, { { 0, 31, height + 0 }, { 32, 1, 64 } }); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_DIVE_LOOP + 6)), + { -16, -16, height }, { { 0, 31, height + 0 }, { 32, 1, 64 } }); + break; + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_DIVE_LOOP + 10)), + { -16, -16, height }, { { 0, 0, height + 0 }, { 32, 1, 64 } }); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_DIVE_LOOP + 14)), + { -16, -16, height }, { { 0, 6, height + 58 }, { 32, 20, 1 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::topCorner, + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 80); + break; + case 5: + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::topCorner, + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_DIVE_LOOP + 3)), + { -16, -16, height }, { { 0, 6, height + 28 }, { 32, 20, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomLeftSide, 0, height + 37, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_DIVE_LOOP + 7)), + { -16, -16, height }, { { 0, 6, height + 28 }, { 32, 20, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopLeftSide, 0, height + 37, session.SupportColours); + break; + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_DIVE_LOOP + 11)), + { -16, -16, height }, { { 0, 6, height + 28 }, { 32, 20, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopRightSide, 0, height + 37, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_DIVE_LOOP + 15)), + { -16, -16, height }, { { 0, 6, height + 28 }, { 32, 20, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomRightSide, 0, height + 37, session.SupportColours); + break; + } + PaintUtilSetGeneralSupportHeight(session, height + 56); + break; + } +} + +static void CorkscrewRCTrackRightEighthDiveLoopUpToOrthogonal( + PaintSession& session, const Ride& ride, uint8_t trackSequence, uint8_t direction, int32_t height, + const TrackElement& trackElement, SupportType supportType) +{ + switch (trackSequence) + { + case 0: + switch (direction) + { + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_DIVE_LOOP + 20)), + { -16, -16, height }, { { 0, 0, height + 48 }, { 32, 32, 1 } }); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_DIVE_LOOP + 28)), + { -16, -16, height }, { { 0, 0, height + -8 }, { 32, 32, 1 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::centre, PaintSegment::topRightSide, PaintSegment::bottomRightSide, + PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 96); + break; + case 1: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_DIVE_LOOP + 24)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 120); + break; + case 2: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_DIVE_LOOP + 16)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 120); + break; + case 3: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_DIVE_LOOP + 17)), + { -16, -16, height }, { { 2, 2, height + 6 }, { 28, 28, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 0, height + 6, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_DIVE_LOOP + 21)), + { -16, -16, height }, { { 31, 0, height + 0 }, { 1, 32, 64 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 0, height + 6, session.SupportColours); + break; + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_DIVE_LOOP + 25)), + { -16, -16, height }, { { 31, 0, height + 0 }, { 1, 32, 64 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 0, height + 6, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_DIVE_LOOP + 29)), + { -16, -16, height }, { { 2, 2, height + 12 }, { 28, 28, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 0, height + 6, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, PaintSegment::centre, + PaintSegment::bottomCorner, PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 112); + break; + case 4: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_DIVE_LOOP + 18)), + { -16, -16, height }, { { 0, 0, height + 0 }, { 1, 32, 64 } }); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_DIVE_LOOP + 22)), + { -16, -16, height }, { { 31, 0, height + 0 }, { 1, 32, 64 } }); + break; + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_DIVE_LOOP + 26)), + { -16, -16, height }, { { 31, 0, height + 0 }, { 1, 32, 64 } }); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_DIVE_LOOP + 30)), + { -16, -16, height }, { { 6, 0, height + 58 }, { 20, 32, 1 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, PaintSegment::centre, + PaintSegment::bottomCorner, PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 80); + break; + case 5: + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, PaintSegment::centre, + PaintSegment::bottomCorner, PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_DIVE_LOOP + 19)), + { -16, -16, height }, { { 6, 0, height + 28 }, { 20, 32, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopLeftSide, 0, height + 37, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_DIVE_LOOP + 23)), + { -16, -16, height }, { { 6, 0, height + 28 }, { 20, 32, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopRightSide, 0, height + 37, session.SupportColours); + break; + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_DIVE_LOOP + 27)), + { -16, -16, height }, { { 6, 0, height + 28 }, { 20, 32, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomRightSide, 0, height + 37, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_CORKSCREW_TRACK_DIVE_LOOP + 31)), + { -16, -16, height }, { { 6, 0, height + 28 }, { 20, 32, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomLeftSide, 0, height + 37, session.SupportColours); + break; + } + PaintUtilSetGeneralSupportHeight(session, height + 56); + break; + } +} + +static void CorkscrewRCTrackLeftEighthDiveLoopDownToDiag( + PaintSession& session, const Ride& ride, uint8_t trackSequence, uint8_t direction, int32_t height, + const TrackElement& trackElement, SupportType supportType) +{ + CorkscrewRCTrackRightEighthDiveLoopUpToOrthogonal( + session, ride, 5 - trackSequence, (direction + 1) & 3, height, trackElement, supportType); +} + +static void CorkscrewRCTrackRightEighthDiveLoopToDownOrthogonal( + PaintSession& session, const Ride& ride, uint8_t trackSequence, uint8_t direction, int32_t height, + const TrackElement& trackElement, SupportType supportType) +{ + CorkscrewRCTrackLeftEighthDiveLoopUpToOrthogonal( + session, ride, 5 - trackSequence, (direction + 2) & 3, height, trackElement, supportType); +} + TrackPaintFunction GetTrackPaintFunctionCorkscrewRC(OpenRCT2::TrackElemType trackType) { switch (trackType) @@ -19654,6 +21050,16 @@ TrackPaintFunction GetTrackPaintFunctionCorkscrewRC(OpenRCT2::TrackElemType trac case TrackElemType::DiagDown60ToFlat: return CorkscrewRCTrackDiag60DegDownToFlat; + // Diagonal large flat to steep + case TrackElemType::DiagFlatToUp60LongBase: + return CorkscrewRCTrackDiagFlatTo60DegUpLongBase; + case TrackElemType::DiagUp60ToFlatLongBase: + return CorkscrewRCTrackDiag60DegUpToFlatLongBase; + case TrackElemType::DiagFlatToDown60LongBase: + return CorkscrewRCTrackDiagFlatTo60DegDownLongBase; + case TrackElemType::DiagDown60ToFlatLongBase: + return CorkscrewRCTrackDiag60DegDownToFlatLongBase; + // Vertical slopes case TrackElemType::Up90: return CorkscrewRCTrack90DegUp; @@ -19926,6 +21332,16 @@ TrackPaintFunction GetTrackPaintFunctionCorkscrewRC(OpenRCT2::TrackElemType trac case TrackElemType::RightLargeZeroGRollDown: return CorkscrewRCTrackRightLargeZeroGRollDown; + // Dive loops + case TrackElemType::LeftEighthDiveLoopUpToOrthogonal: + return CorkscrewRCTrackLeftEighthDiveLoopUpToOrthogonal; + case TrackElemType::RightEighthDiveLoopUpToOrthogonal: + return CorkscrewRCTrackRightEighthDiveLoopUpToOrthogonal; + case TrackElemType::LeftEighthDiveLoopDownToDiag: + return CorkscrewRCTrackLeftEighthDiveLoopDownToDiag; + case TrackElemType::RightEighthDiveLoopDownToDiag: + return CorkscrewRCTrackRightEighthDiveLoopToDownOrthogonal; + default: return TrackPaintFunctionDummy; } diff --git a/src/openrct2/paint/track/coaster/LatticeTriangleTrack.cpp b/src/openrct2/paint/track/coaster/LatticeTriangleTrack.cpp index 17df6164f0..4a7ee96143 100644 --- a/src/openrct2/paint/track/coaster/LatticeTriangleTrack.cpp +++ b/src/openrct2/paint/track/coaster/LatticeTriangleTrack.cpp @@ -18433,6 +18433,1422 @@ static void LatticeTriangleTrackDiagBooster( TrackPaintUtilDiagTilesPaintExtra(session, 3, height, direction, trackSequence, images, supportType.metal); } +static void LatticeTriangleTrackDiagFlatTo60DegUpLongBase( + PaintSession& session, const Ride& ride, uint8_t trackSequence, uint8_t direction, int32_t height, + const TrackElement& trackElement, SupportType supportType) +{ + switch (trackSequence) + { + case 0: + switch (direction) + { + case 3: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 9)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::centre, PaintSegment::topRightSide, PaintSegment::bottomRightSide, + PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 32); + break; + case 1: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 0)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 48); + break; + case 2: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 6)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 48); + break; + case 3: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 0, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 3)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 0, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 0, height + 0, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 10)), + { -16, -16, height }, { { -20, -20, height + 8 }, { 24, 24, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 0, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, PaintSegment::centre, + PaintSegment::topRightSide, PaintSegment::bottomRightSide, PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 64); + break; + case 4: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 1)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 72); + break; + case 5: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 7)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 72); + break; + case 6: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 11, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 4)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 11, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 11, height + 0, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 11)), + { -16, -16, height }, { { -16, -16, height + 32 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 11, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, PaintSegment::centre, + PaintSegment::topRightSide, PaintSegment::bottomRightSide, PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 96); + break; + case 7: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 2)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 120); + break; + case 8: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 8)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 120); + break; + case 9: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 19, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 5)), + { -16, -16, height }, { { -16, -16, height + 80 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 19, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 19, height + 0, session.SupportColours); + break; + case 3: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 19, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, + PaintSegment::centre), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 136); + break; + } +} + +static void LatticeTriangleTrackDiag60DegUpToFlatLongBase( + PaintSession& session, const Ride& ride, uint8_t trackSequence, uint8_t direction, int32_t height, + const TrackElement& trackElement, SupportType supportType) +{ + switch (trackSequence) + { + case 0: + switch (direction) + { + case 3: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 21)), + { -16, -16, height }, { { -8, -8, height + 0 }, { 16, 16, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::centre, PaintSegment::topRightSide, PaintSegment::bottomRightSide, + PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 96); + break; + case 1: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 12)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 104); + break; + case 2: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 18)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 104); + break; + case 3: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 28, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 15)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 28, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 28, height + 0, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 22)), + { -16, -16, height }, { { -8, -8, height + 56 }, { 16, 16, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 28, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, PaintSegment::centre, + PaintSegment::topRightSide, PaintSegment::bottomRightSide, PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 112); + break; + case 4: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 13)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 64); + break; + case 5: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 19)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 64); + break; + case 6: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 10, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 16)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 10, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 10, height + 0, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 23)), + { -16, -16, height }, { { -16, -16, height + 24 }, { 24, 24, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 10, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, PaintSegment::centre, + PaintSegment::topRightSide, PaintSegment::bottomRightSide, PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 40); + break; + case 7: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 14)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 40); + break; + case 8: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 20)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 40); + break; + case 9: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 3, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 17)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 3, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 3, height + 0, session.SupportColours); + break; + case 3: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 3, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, + PaintSegment::centre), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 40); + break; + } +} + +static void LatticeTriangleTrackDiagFlatTo60DegDownLongBase( + PaintSession& session, const Ride& ride, uint8_t trackSequence, uint8_t direction, int32_t height, + const TrackElement& trackElement, SupportType supportType) +{ + switch (trackSequence) + { + case 0: + switch (direction) + { + case 3: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 17)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::centre, PaintSegment::topRightSide, PaintSegment::bottomRightSide, + PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 40); + break; + case 1: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 20)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 40); + break; + case 2: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 14)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 40); + break; + case 3: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 24, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 23)), + { -16, -16, height }, { { -16, -16, height + 24 }, { 24, 24, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 24, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 24, height + 0, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 16)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 24, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, PaintSegment::centre, + PaintSegment::topRightSide, PaintSegment::bottomRightSide, PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 40); + break; + case 4: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 19)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 64); + break; + case 5: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 13)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 64); + break; + case 6: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 58, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 22)), + { -16, -16, height }, { { -8, -8, height + 56 }, { 16, 16, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 58, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 58, height + 0, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 15)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 58, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, PaintSegment::centre, + PaintSegment::topRightSide, PaintSegment::bottomRightSide, PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 112); + break; + case 7: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 18)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 104); + break; + case 8: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 12)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 104); + break; + case 9: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 14, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 21)), + { -16, -16, height }, { { -8, -8, height + 0 }, { 16, 16, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 14, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 14, height + 0, session.SupportColours); + break; + case 3: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 14, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, + PaintSegment::centre), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 96); + break; + } +} + +static void LatticeTriangleTrackDiag60DegDownToFlatLongBase( + PaintSession& session, const Ride& ride, uint8_t trackSequence, uint8_t direction, int32_t height, + const TrackElement& trackElement, SupportType supportType) +{ + switch (trackSequence) + { + case 0: + switch (direction) + { + case 3: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 5)), + { -16, -16, height }, { { -16, -16, height + 80 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::centre, PaintSegment::topRightSide, PaintSegment::bottomRightSide, + PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 136); + break; + case 1: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 8)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 120); + break; + case 2: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 2)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 120); + break; + case 3: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 38, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 11)), + { -16, -16, height }, { { -16, -16, height + 32 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 38, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 38, height + 0, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 4)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 38, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, PaintSegment::centre, + PaintSegment::topRightSide, PaintSegment::bottomRightSide, PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 96); + break; + case 4: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 7)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 72); + break; + case 5: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 1)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 72); + break; + case 6: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 12, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 10)), + { -16, -16, height }, { { -8, -8, height + 8 }, { 24, 24, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 12, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 12, height + 0, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 3)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 12, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, PaintSegment::centre, + PaintSegment::topRightSide, PaintSegment::bottomRightSide, PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 64); + break; + case 7: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 6)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 48); + break; + case 8: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 0)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 48); + break; + case 9: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 0, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 9)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 0, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 0, height + 0, session.SupportColours); + break; + case 3: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 0, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, + PaintSegment::centre), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 32); + break; + } +} + +static void LatticeTriangleTrackLeftEighthDiveLoopUpToOrthogonal( + PaintSession& session, const Ride& ride, uint8_t trackSequence, uint8_t direction, int32_t height, + const TrackElement& trackElement, SupportType supportType) +{ + switch (trackSequence) + { + case 0: + switch (direction) + { + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_DIVE_LOOP + 4)), + { -16, -16, height }, { { 0, 0, height + 48 }, { 32, 32, 1 } }); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_DIVE_LOOP + 12)), + { -16, -16, height }, { { 0, 0, height + -8 }, { 32, 32, 1 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::centre, PaintSegment::topRightSide, PaintSegment::bottomRightSide, + PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 96); + break; + case 1: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_DIVE_LOOP + 0)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 120); + break; + case 2: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_DIVE_LOOP + 8)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 120); + break; + case 3: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_DIVE_LOOP + 1)), + { -16, -16, height }, { { 0, 31, height + 0 }, { 32, 1, 64 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 0, height + 4, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_DIVE_LOOP + 5)), + { -16, -16, height }, { { 0, 31, height + 0 }, { 32, 1, 64 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 0, height + 4, session.SupportColours); + break; + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_DIVE_LOOP + 9)), + { -16, -16, height }, { { 2, 2, height + 4 }, { 28, 28, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 0, height + 4, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_DIVE_LOOP + 13)), + { -16, -16, height }, { { 2, 2, height + 12 }, { 28, 28, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 0, height + 4, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::topCorner, + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 112); + break; + case 4: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_DIVE_LOOP + 2)), + { -16, -16, height }, { { 0, 31, height + 0 }, { 32, 1, 64 } }); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_DIVE_LOOP + 6)), + { -16, -16, height }, { { 0, 31, height + 0 }, { 32, 1, 64 } }); + break; + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_DIVE_LOOP + 10)), + { -16, -16, height }, { { 0, 0, height + 0 }, { 32, 1, 64 } }); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_DIVE_LOOP + 14)), + { -16, -16, height }, { { 0, 6, height + 58 }, { 32, 20, 1 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::topCorner, + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 80); + break; + case 5: + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::topCorner, + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_DIVE_LOOP + 3)), + { -16, -16, height }, { { 0, 6, height + 36 }, { 32, 20, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomLeftSide, 0, height + 44, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_DIVE_LOOP + 7)), + { -16, -16, height }, { { 0, 6, height + 36 }, { 32, 20, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopLeftSide, 0, height + 44, session.SupportColours); + break; + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_DIVE_LOOP + 11)), + { -16, -16, height }, { { 0, 6, height + 36 }, { 32, 20, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopRightSide, 0, height + 44, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_DIVE_LOOP + 15)), + { -16, -16, height }, { { 0, 6, height + 36 }, { 32, 20, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomRightSide, 0, height + 44, session.SupportColours); + break; + } + PaintUtilSetGeneralSupportHeight(session, height + 56); + break; + } +} + +static void LatticeTriangleTrackRightEighthDiveLoopUpToOrthogonal( + PaintSession& session, const Ride& ride, uint8_t trackSequence, uint8_t direction, int32_t height, + const TrackElement& trackElement, SupportType supportType) +{ + switch (trackSequence) + { + case 0: + switch (direction) + { + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_DIVE_LOOP + 20)), + { -16, -16, height }, { { 0, 0, height + 48 }, { 32, 32, 1 } }); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_DIVE_LOOP + 28)), + { -16, -16, height }, { { 0, 0, height + -8 }, { 32, 32, 1 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::centre, PaintSegment::topRightSide, PaintSegment::bottomRightSide, + PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 96); + break; + case 1: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_DIVE_LOOP + 24)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 120); + break; + case 2: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_DIVE_LOOP + 16)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 120); + break; + case 3: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_DIVE_LOOP + 17)), + { -16, -16, height }, { { 2, 2, height + 4 }, { 28, 28, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 0, height + 4, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_DIVE_LOOP + 21)), + { -16, -16, height }, { { 31, 0, height + 0 }, { 1, 32, 64 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 0, height + 4, session.SupportColours); + break; + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_DIVE_LOOP + 25)), + { -16, -16, height }, { { 31, 0, height + 0 }, { 1, 32, 64 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 0, height + 4, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_DIVE_LOOP + 29)), + { -16, -16, height }, { { 2, 2, height + 12 }, { 28, 28, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 0, height + 4, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, PaintSegment::centre, + PaintSegment::bottomCorner, PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 112); + break; + case 4: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_DIVE_LOOP + 18)), + { -16, -16, height }, { { 0, 0, height + 0 }, { 1, 32, 64 } }); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_DIVE_LOOP + 22)), + { -16, -16, height }, { { 31, 0, height + 0 }, { 1, 32, 64 } }); + break; + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_DIVE_LOOP + 26)), + { -16, -16, height }, { { 31, 0, height + 0 }, { 1, 32, 64 } }); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_DIVE_LOOP + 30)), + { -16, -16, height }, { { 6, 0, height + 58 }, { 20, 32, 1 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, PaintSegment::centre, + PaintSegment::bottomCorner, PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 80); + break; + case 5: + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, PaintSegment::centre, + PaintSegment::bottomCorner, PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_DIVE_LOOP + 19)), + { -16, -16, height }, { { 6, 0, height + 36 }, { 20, 32, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopLeftSide, 0, height + 44, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_DIVE_LOOP + 23)), + { -16, -16, height }, { { 6, 0, height + 36 }, { 20, 32, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopRightSide, 0, height + 44, session.SupportColours); + break; + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_DIVE_LOOP + 27)), + { -16, -16, height }, { { 6, 0, height + 36 }, { 20, 32, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomRightSide, 0, height + 44, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_LATTICE_TRIANGLE_TRACK_DIVE_LOOP + 31)), + { -16, -16, height }, { { 6, 0, height + 36 }, { 20, 32, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomLeftSide, 0, height + 44, session.SupportColours); + break; + } + PaintUtilSetGeneralSupportHeight(session, height + 56); + break; + } +} + +static void LatticeTriangleTrackLeftEighthDiveLoopDownToDiag( + PaintSession& session, const Ride& ride, uint8_t trackSequence, uint8_t direction, int32_t height, + const TrackElement& trackElement, SupportType supportType) +{ + LatticeTriangleTrackRightEighthDiveLoopUpToOrthogonal( + session, ride, 5 - trackSequence, (direction + 1) & 3, height, trackElement, supportType); +} + +static void LatticeTriangleTrackRightEighthDiveLoopToDownOrthogonal( + PaintSession& session, const Ride& ride, uint8_t trackSequence, uint8_t direction, int32_t height, + const TrackElement& trackElement, SupportType supportType) +{ + LatticeTriangleTrackLeftEighthDiveLoopUpToOrthogonal( + session, ride, 5 - trackSequence, (direction + 2) & 3, height, trackElement, supportType); +} + TrackPaintFunction GetTrackPaintFunctionLatticeTriangleTrack(OpenRCT2::TrackElemType trackType) { switch (trackType) @@ -18787,6 +20203,16 @@ TrackPaintFunction GetTrackPaintFunctionLatticeTriangleTrack(OpenRCT2::TrackElem return LatticeTriangleTrackLeftLargeZeroGRollDown; case TrackElemType::RightLargeZeroGRollDown: return LatticeTriangleTrackRightLargeZeroGRollDown; + + case TrackElemType::LeftEighthDiveLoopUpToOrthogonal: + return LatticeTriangleTrackLeftEighthDiveLoopUpToOrthogonal; + case TrackElemType::RightEighthDiveLoopUpToOrthogonal: + return LatticeTriangleTrackRightEighthDiveLoopUpToOrthogonal; + case TrackElemType::LeftEighthDiveLoopDownToDiag: + return LatticeTriangleTrackLeftEighthDiveLoopDownToDiag; + case TrackElemType::RightEighthDiveLoopDownToDiag: + return LatticeTriangleTrackRightEighthDiveLoopToDownOrthogonal; + case TrackElemType::Up90ToInvertedFlatQuarterLoop: return LatticeTriangleTrack90DegToInvertedFlatQuarterLoopUp; case TrackElemType::InvertedFlatToDown90QuarterLoop: @@ -18831,6 +20257,14 @@ TrackPaintFunction GetTrackPaintFunctionLatticeTriangleTrack(OpenRCT2::TrackElem return LatticeTriangleTrackDiagFlatTo60DegDown; case TrackElemType::DiagDown60ToFlat: return LatticeTriangleTrackDiag60DegDownToFlat; + case TrackElemType::DiagFlatToUp60LongBase: + return LatticeTriangleTrackDiagFlatTo60DegUpLongBase; + case TrackElemType::DiagUp60ToFlatLongBase: + return LatticeTriangleTrackDiag60DegUpToFlatLongBase; + case TrackElemType::DiagFlatToDown60LongBase: + return LatticeTriangleTrackDiagFlatTo60DegDownLongBase; + case TrackElemType::DiagDown60ToFlatLongBase: + return LatticeTriangleTrackDiag60DegDownToFlatLongBase; case TrackElemType::LeftEighthToDiagUp25: return LatticeTriangleTrackLeftEighthToDiagUp25; case TrackElemType::RightEighthToDiagUp25: diff --git a/src/openrct2/paint/track/coaster/SingleRailRollerCoaster.cpp b/src/openrct2/paint/track/coaster/SingleRailRollerCoaster.cpp index 10d45b6963..be17785b14 100644 --- a/src/openrct2/paint/track/coaster/SingleRailRollerCoaster.cpp +++ b/src/openrct2/paint/track/coaster/SingleRailRollerCoaster.cpp @@ -18531,6 +18531,1459 @@ namespace OpenRCT2::SingleRailRC PaintUtilSetGeneralSupportHeight(session, height + 56); } + static void TrackDiagFlatTo60DegUpLongBase( + PaintSession& session, const Ride& ride, uint8_t trackSequence, uint8_t direction, int32_t height, + const TrackElement& trackElement, SupportType supportType) + { + switch (trackSequence) + { + case 0: + switch (direction) + { + case 3: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 9)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::centre, PaintSegment::topRightSide, PaintSegment::bottomRightSide, + PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 32); + break; + case 1: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 0)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, + PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 48); + break; + case 2: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 6)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 48); + break; + case 3: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 0, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 3)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 0, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 0, height + 0, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 10)), + { -16, -16, height }, { { -20, -20, height + 8 }, { 24, 24, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 0, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, + PaintSegment::centre, PaintSegment::topRightSide, PaintSegment::bottomRightSide, + PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 64); + break; + case 4: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 1)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, + PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 72); + break; + case 5: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 7)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 72); + break; + case 6: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 16, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 4)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 16, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 16, height + 0, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 11)), + { -16, -16, height }, { { -16, -16, height + 32 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 16, height + 0, + session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, + PaintSegment::centre, PaintSegment::topRightSide, PaintSegment::bottomRightSide, + PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 96); + break; + case 7: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 2)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, + PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 120); + break; + case 8: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 8)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 120); + break; + case 9: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 24, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 5)), + { -16, -16, height }, { { -16, -16, height + 80 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 24, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 24, height + 0, session.SupportColours); + break; + case 3: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 24, height + 0, + session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, + PaintSegment::centre), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 136); + break; + } + } + + static void TrackDiag60DegUpToFlatLongBase( + PaintSession& session, const Ride& ride, uint8_t trackSequence, uint8_t direction, int32_t height, + const TrackElement& trackElement, SupportType supportType) + { + switch (trackSequence) + { + case 0: + switch (direction) + { + case 3: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 21)), + { -16, -16, height }, { { -8, -8, height + 0 }, { 16, 16, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::centre, PaintSegment::topRightSide, PaintSegment::bottomRightSide, + PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 96); + break; + case 1: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 12)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, + PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 104); + break; + case 2: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 18)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 104); + break; + case 3: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 33, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 15)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 33, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 33, height + 0, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 22)), + { -16, -16, height }, { { -8, -8, height + 56 }, { 16, 16, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 33, height + 0, + session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, + PaintSegment::centre, PaintSegment::topRightSide, PaintSegment::bottomRightSide, + PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 112); + break; + case 4: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 13)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, + PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 64); + break; + case 5: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 19)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 64); + break; + case 6: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 15, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 16)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 15, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 15, height + 0, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 23)), + { -16, -16, height }, { { -16, -16, height + 24 }, { 24, 24, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 15, height + 0, + session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, + PaintSegment::centre, PaintSegment::topRightSide, PaintSegment::bottomRightSide, + PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 40); + break; + case 7: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 14)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, + PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 40); + break; + case 8: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 20)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 40); + break; + case 9: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 8, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 17)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 8, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 8, height + 0, session.SupportColours); + break; + case 3: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 8, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, + PaintSegment::centre), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 40); + break; + } + } + + static void TrackDiagFlatTo60DegDownLongBase( + PaintSession& session, const Ride& ride, uint8_t trackSequence, uint8_t direction, int32_t height, + const TrackElement& trackElement, SupportType supportType) + { + switch (trackSequence) + { + case 0: + switch (direction) + { + case 3: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 17)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::centre, PaintSegment::topRightSide, PaintSegment::bottomRightSide, + PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 40); + break; + case 1: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 20)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, + PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 40); + break; + case 2: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 14)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 40); + break; + case 3: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 29, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 23)), + { -16, -16, height }, { { -16, -16, height + 24 }, { 24, 24, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 29, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 29, height + 0, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 16)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 29, height + 0, + session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, + PaintSegment::centre, PaintSegment::topRightSide, PaintSegment::bottomRightSide, + PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 40); + break; + case 4: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 19)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, + PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 64); + break; + case 5: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 13)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 64); + break; + case 6: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 63, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 22)), + { -16, -16, height }, { { -8, -8, height + 56 }, { 16, 16, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 63, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 63, height + 0, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 15)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 63, height + 0, + session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, + PaintSegment::centre, PaintSegment::topRightSide, PaintSegment::bottomRightSide, + PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 112); + break; + case 7: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 18)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, + PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 104); + break; + case 8: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 12)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 104); + break; + case 9: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 19, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 21)), + { -16, -16, height }, { { -8, -8, height + 0 }, { 16, 16, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 19, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 19, height + 0, session.SupportColours); + break; + case 3: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 19, height + 0, + session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, + PaintSegment::centre), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 96); + break; + } + } + + static void TrackDiag60DegDownToFlatLongBase( + PaintSession& session, const Ride& ride, uint8_t trackSequence, uint8_t direction, int32_t height, + const TrackElement& trackElement, SupportType supportType) + { + switch (trackSequence) + { + case 0: + switch (direction) + { + case 3: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 5)), + { -16, -16, height }, { { -16, -16, height + 80 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::centre, PaintSegment::topRightSide, PaintSegment::bottomRightSide, + PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 136); + break; + case 1: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 8)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, + PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 120); + break; + case 2: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 2)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 120); + break; + case 3: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 43, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 11)), + { -16, -16, height }, { { -16, -16, height + 32 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 43, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 43, height + 0, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 4)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 43, height + 0, + session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, + PaintSegment::centre, PaintSegment::topRightSide, PaintSegment::bottomRightSide, + PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 96); + break; + case 4: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 7)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, + PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 72); + break; + case 5: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 1)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 72); + break; + case 6: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 17, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 10)), + { -16, -16, height }, { { -8, -8, height + 8 }, { 24, 24, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 17, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 17, height + 0, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 3)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 17, height + 0, + session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, + PaintSegment::centre, PaintSegment::topRightSide, PaintSegment::bottomRightSide, + PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 64); + break; + case 7: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 6)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, + PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 48); + break; + case 8: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 0)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 48); + break; + case 9: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 0, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, + session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 9)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 0, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 0, height + 0, session.SupportColours); + break; + case 3: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 0, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, + PaintSegment::centre), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 32); + break; + } + } + + static void TrackLeftEighthDiveLoopUpToOrthogonal( + PaintSession& session, const Ride& ride, uint8_t trackSequence, uint8_t direction, int32_t height, + const TrackElement& trackElement, SupportType supportType) + { + switch (trackSequence) + { + case 0: + switch (direction) + { + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_DIVE_LOOP + 4)), + { -16, -16, height }, { { 0, 0, height + 44 }, { 32, 32, 1 } }); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_DIVE_LOOP + 12)), + { -16, -16, height }, { { 0, 0, height + -8 }, { 32, 32, 1 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::centre, PaintSegment::topRightSide, PaintSegment::bottomRightSide, + PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 96); + break; + case 1: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_DIVE_LOOP + 0)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, + PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 120); + break; + case 2: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_DIVE_LOOP + 8)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 120); + break; + case 3: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_DIVE_LOOP + 1)), + { -16, -16, height }, { { 0, 31, height + 0 }, { 32, 1, 64 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 0, height + 14, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_DIVE_LOOP + 5)), + { -16, -16, height }, { { 0, 31, height + 0 }, { 32, 1, 64 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 0, height + 9, session.SupportColours); + break; + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_DIVE_LOOP + 9)), + { -16, -16, height }, { { 2, 2, height + 8 }, { 28, 28, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 0, height + 9, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_DIVE_LOOP + 13)), + { -16, -16, height }, { { 2, 2, height + 12 }, { 28, 28, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 0, height + 9, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::topCorner, + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 112); + break; + case 4: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_DIVE_LOOP + 2)), + { -16, -16, height }, { { 0, 31, height + 0 }, { 32, 1, 64 } }); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_DIVE_LOOP + 6)), + { -16, -16, height }, { { 0, 31, height + 0 }, { 32, 1, 64 } }); + break; + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_DIVE_LOOP + 10)), + { -16, -16, height }, { { 0, 0, height + 0 }, { 32, 1, 64 } }); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_DIVE_LOOP + 14)), + { -16, -16, height }, { { 0, 6, height + 58 }, { 32, 20, 1 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::topCorner, + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 80); + break; + case 5: + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::topCorner, + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_DIVE_LOOP + 3)), + { -16, -16, height }, { { 0, 6, height + 26 }, { 32, 20, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomLeftSide, 0, height + 33, + session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_DIVE_LOOP + 7)), + { -16, -16, height }, { { 0, 6, height + 26 }, { 32, 20, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopLeftSide, 0, height + 33, session.SupportColours); + break; + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_DIVE_LOOP + 11)), + { -16, -16, height }, { { 0, 6, height + 26 }, { 32, 20, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopRightSide, 0, height + 33, + session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_DIVE_LOOP + 15)), + { -16, -16, height }, { { 0, 6, height + 26 }, { 32, 20, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomRightSide, 0, height + 33, + session.SupportColours); + break; + } + PaintUtilSetGeneralSupportHeight(session, height + 56); + break; + } + } + + static void TrackRightEighthDiveLoopUpToOrthogonal( + PaintSession& session, const Ride& ride, uint8_t trackSequence, uint8_t direction, int32_t height, + const TrackElement& trackElement, SupportType supportType) + { + switch (trackSequence) + { + case 0: + switch (direction) + { + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_DIVE_LOOP + 20)), + { -16, -16, height }, { { 0, 0, height + 44 }, { 32, 32, 1 } }); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_DIVE_LOOP + 28)), + { -16, -16, height }, { { 0, 0, height + -8 }, { 32, 32, 1 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::centre, PaintSegment::topRightSide, PaintSegment::bottomRightSide, + PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 96); + break; + case 1: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_DIVE_LOOP + 24)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 120); + break; + case 2: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_DIVE_LOOP + 16)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, + PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 120); + break; + case 3: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_DIVE_LOOP + 17)), + { -16, -16, height }, { { 2, 2, height + 8 }, { 28, 28, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 0, height + 9, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_DIVE_LOOP + 21)), + { -16, -16, height }, { { 31, 0, height + 0 }, { 1, 32, 64 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 0, height + 9, session.SupportColours); + break; + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_DIVE_LOOP + 25)), + { -16, -16, height }, { { 31, 0, height + 0 }, { 1, 32, 64 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 0, height + 14, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_DIVE_LOOP + 29)), + { -16, -16, height }, { { 2, 2, height + 12 }, { 28, 28, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 0, height + 9, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, + PaintSegment::centre, PaintSegment::bottomCorner, PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 112); + break; + case 4: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_DIVE_LOOP + 18)), + { -16, -16, height }, { { 0, 0, height + 0 }, { 1, 32, 64 } }); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_DIVE_LOOP + 22)), + { -16, -16, height }, { { 31, 0, height + 0 }, { 1, 32, 64 } }); + break; + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_DIVE_LOOP + 26)), + { -16, -16, height }, { { 31, 0, height + 0 }, { 1, 32, 64 } }); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_DIVE_LOOP + 30)), + { -16, -16, height }, { { 6, 0, height + 58 }, { 20, 32, 1 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, + PaintSegment::centre, PaintSegment::bottomCorner, PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 80); + break; + case 5: + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, + PaintSegment::centre, PaintSegment::bottomCorner, PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_DIVE_LOOP + 19)), + { -16, -16, height }, { { 6, 0, height + 26 }, { 20, 32, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopLeftSide, 0, height + 33, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_DIVE_LOOP + 23)), + { -16, -16, height }, { { 6, 0, height + 26 }, { 20, 32, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopRightSide, 0, height + 33, + session.SupportColours); + break; + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_DIVE_LOOP + 27)), + { -16, -16, height }, { { 6, 0, height + 26 }, { 20, 32, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomRightSide, 0, height + 33, + session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_SINGLE_RAIL_TRACK_DIVE_LOOP + 31)), + { -16, -16, height }, { { 6, 0, height + 26 }, { 20, 32, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomLeftSide, 0, height + 33, + session.SupportColours); + break; + } + PaintUtilSetGeneralSupportHeight(session, height + 56); + break; + } + } + + static void TrackLeftEighthDiveLoopDownToDiag( + PaintSession& session, const Ride& ride, uint8_t trackSequence, uint8_t direction, int32_t height, + const TrackElement& trackElement, SupportType supportType) + { + TrackRightEighthDiveLoopUpToOrthogonal( + session, ride, 5 - trackSequence, (direction + 1) & 3, height, trackElement, supportType); + } + + static void TrackRightEighthDiveLoopToDownOrthogonal( + PaintSession& session, const Ride& ride, uint8_t trackSequence, uint8_t direction, int32_t height, + const TrackElement& trackElement, SupportType supportType) + { + TrackLeftEighthDiveLoopUpToOrthogonal( + session, ride, 5 - trackSequence, (direction + 2) & 3, height, trackElement, supportType); + } + TrackPaintFunction GetTrackPaintFunction(OpenRCT2::TrackElemType trackType) { switch (trackType) @@ -18877,6 +20330,14 @@ namespace OpenRCT2::SingleRailRC return TrackLeftLargeZeroGRollDown; case TrackElemType::RightLargeZeroGRollDown: return TrackRightLargeZeroGRollDown; + case TrackElemType::LeftEighthDiveLoopUpToOrthogonal: + return TrackLeftEighthDiveLoopUpToOrthogonal; + case TrackElemType::RightEighthDiveLoopUpToOrthogonal: + return TrackRightEighthDiveLoopUpToOrthogonal; + case TrackElemType::LeftEighthDiveLoopDownToDiag: + return TrackLeftEighthDiveLoopDownToDiag; + case TrackElemType::RightEighthDiveLoopDownToDiag: + return TrackRightEighthDiveLoopToDownOrthogonal; case TrackElemType::Up90ToInvertedFlatQuarterLoop: return Track90DegToInvertedFlatQuarterLoopUp; case TrackElemType::InvertedFlatToDown90QuarterLoop: @@ -18921,6 +20382,14 @@ namespace OpenRCT2::SingleRailRC return TrackDiagFlatTo60DegDown; case TrackElemType::DiagDown60ToFlat: return TrackDiag60DegDownToFlat; + case TrackElemType::DiagFlatToUp60LongBase: + return TrackDiagFlatTo60DegUpLongBase; + case TrackElemType::DiagUp60ToFlatLongBase: + return TrackDiag60DegUpToFlatLongBase; + case TrackElemType::DiagFlatToDown60LongBase: + return TrackDiagFlatTo60DegDownLongBase; + case TrackElemType::DiagDown60ToFlatLongBase: + return TrackDiag60DegDownToFlatLongBase; case TrackElemType::LeftEighthToDiagUp25: return TrackLeftEighthToDiagUp25; diff --git a/src/openrct2/paint/track/coaster/TwisterRollerCoaster.cpp b/src/openrct2/paint/track/coaster/TwisterRollerCoaster.cpp index e34431361f..8b48e2c18e 100644 --- a/src/openrct2/paint/track/coaster/TwisterRollerCoaster.cpp +++ b/src/openrct2/paint/track/coaster/TwisterRollerCoaster.cpp @@ -19009,6 +19009,1374 @@ static void TwisterRCTrackRightLargeZeroGRollDown( session, ride, 3 - trackSequence, (direction + 2) & 3, height, trackElement, supportType); } +static void TwisterRCTrackDiagFlatTo60DegUpLongBase( + PaintSession& session, const Ride& ride, uint8_t trackSequence, uint8_t direction, int32_t height, + const TrackElement& trackElement, SupportType supportType) +{ + switch (trackSequence) + { + case 0: + switch (direction) + { + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 9)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::centre, PaintSegment::topRightSide, PaintSegment::bottomRightSide, + PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 32); + break; + case 1: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 0)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 48); + break; + case 2: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 6)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 48); + break; + case 3: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 0, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 3)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 0, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 0, height + 0, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 10)), + { -16, -16, height }, { { -20, -20, height + 8 }, { 24, 24, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 0, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, PaintSegment::centre, + PaintSegment::topRightSide, PaintSegment::bottomRightSide, PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 64); + break; + case 4: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 1)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 72); + break; + case 5: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 7)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 72); + break; + case 6: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 11, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 4)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 11, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 11, height + 0, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 11)), + { -16, -16, height }, { { -16, -16, height + 32 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 11, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, PaintSegment::centre, + PaintSegment::topRightSide, PaintSegment::bottomRightSide, PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 96); + break; + case 7: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 2)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 120); + break; + case 8: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 8)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 120); + break; + case 9: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 19, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 5)), + { -16, -16, height }, { { -16, -16, height + 80 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 19, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 19, height + 0, session.SupportColours); + break; + case 3: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 19, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, + PaintSegment::centre), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 136); + break; + } +} + +static void TwisterRCTrackDiag60DegUpToFlatLongBase( + PaintSession& session, const Ride& ride, uint8_t trackSequence, uint8_t direction, int32_t height, + const TrackElement& trackElement, SupportType supportType) +{ + switch (trackSequence) + { + case 0: + switch (direction) + { + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 21)), + { -16, -16, height }, { { -8, -8, height + 0 }, { 16, 16, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::centre, PaintSegment::topRightSide, PaintSegment::bottomRightSide, + PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 96); + break; + case 1: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 12)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 104); + break; + case 2: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 18)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 104); + break; + case 3: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 28, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 15)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 28, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 28, height + 0, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 22)), + { -16, -16, height }, { { -8, -8, height + 56 }, { 16, 16, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 28, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, PaintSegment::centre, + PaintSegment::topRightSide, PaintSegment::bottomRightSide, PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 112); + break; + case 4: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 13)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 64); + break; + case 5: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 19)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 64); + break; + case 6: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 10, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 16)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 10, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 10, height + 0, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 23)), + { -16, -16, height }, { { -16, -16, height + 24 }, { 24, 24, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 10, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, PaintSegment::centre, + PaintSegment::topRightSide, PaintSegment::bottomRightSide, PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 40); + break; + case 7: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 14)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 40); + break; + case 8: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 20)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 40); + break; + case 9: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 3, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 17)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 3, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 3, height + 0, session.SupportColours); + break; + case 3: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 3, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, + PaintSegment::centre), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 40); + break; + } +} + +static void TwisterRCTrackDiagFlatTo60DegDownLongBase( + PaintSession& session, const Ride& ride, uint8_t trackSequence, uint8_t direction, int32_t height, + const TrackElement& trackElement, SupportType supportType) +{ + switch (trackSequence) + { + case 0: + switch (direction) + { + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 17)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::centre, PaintSegment::topRightSide, PaintSegment::bottomRightSide, + PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 40); + break; + case 1: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 20)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 40); + break; + case 2: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 14)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 40); + break; + case 3: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 24, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 23)), + { -16, -16, height }, { { -16, -16, height + 24 }, { 24, 24, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 24, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 24, height + 0, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 16)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 24, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, PaintSegment::centre, + PaintSegment::topRightSide, PaintSegment::bottomRightSide, PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 40); + break; + case 4: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 19)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 64); + break; + case 5: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 13)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 64); + break; + case 6: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 58, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 22)), + { -16, -16, height }, { { -8, -8, height + 56 }, { 16, 16, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 58, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 58, height + 0, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 15)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 58, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, PaintSegment::centre, + PaintSegment::topRightSide, PaintSegment::bottomRightSide, PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 112); + break; + case 7: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 18)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 104); + break; + case 8: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 12)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 104); + break; + case 9: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 14, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 21)), + { -16, -16, height }, { { -8, -8, height + 0 }, { 16, 16, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 14, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 14, height + 0, session.SupportColours); + break; + case 3: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 14, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, + PaintSegment::centre), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 96); + break; + } +} + +static void TwisterRCTrackDiag60DegDownToFlatLongBase( + PaintSession& session, const Ride& ride, uint8_t trackSequence, uint8_t direction, int32_t height, + const TrackElement& trackElement, SupportType supportType) +{ + switch (trackSequence) + { + case 0: + switch (direction) + { + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 5)), + { -16, -16, height }, { { -16, -16, height + 80 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::centre, PaintSegment::topRightSide, PaintSegment::bottomRightSide, + PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 136); + break; + case 1: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 8)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 120); + break; + case 2: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 2)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 120); + break; + case 3: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 38, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 11)), + { -16, -16, height }, { { -16, -16, height + 32 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 38, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 38, height + 0, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 4)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 38, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, PaintSegment::centre, + PaintSegment::topRightSide, PaintSegment::bottomRightSide, PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 96); + break; + case 4: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 7)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 72); + break; + case 5: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 1)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 72); + break; + case 6: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 12, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 10)), + { -16, -16, height }, { { -8, -8, height + 8 }, { 24, 24, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 12, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 12, height + 0, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 3)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 12, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, PaintSegment::centre, + PaintSegment::topRightSide, PaintSegment::bottomRightSide, PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 64); + break; + case 7: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 6)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 48); + break; + case 8: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 0)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 48); + break; + case 9: + switch (direction) + { + case 0: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 0, height + 0, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 9)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 0, height + 0, session.SupportColours); + break; + case 2: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 0, height + 0, session.SupportColours); + break; + case 3: + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 0, height + 0, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, + PaintSegment::centre), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 32); + break; + } +} + +static void TwisterRCTrackLeftEighthDiveLoopUpToOrthogonal( + PaintSession& session, const Ride& ride, uint8_t trackSequence, uint8_t direction, int32_t height, + const TrackElement& trackElement, SupportType supportType) +{ + switch (trackSequence) + { + case 0: + switch (direction) + { + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_DIVE_LOOP + 4)), + { -16, -16, height }, { { 0, 0, height + 48 }, { 32, 32, 1 } }); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_DIVE_LOOP + 12)), + { -16, -16, height }, { { 0, 0, height + -8 }, { 32, 32, 1 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::centre, PaintSegment::topRightSide, PaintSegment::bottomRightSide, + PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 96); + break; + case 1: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_DIVE_LOOP + 0)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 120); + break; + case 2: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_DIVE_LOOP + 8)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 120); + break; + case 3: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_DIVE_LOOP + 1)), + { -16, -16, height }, { { 0, 31, height + 0 }, { 32, 1, 64 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 0, height + 4, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_DIVE_LOOP + 5)), + { -16, -16, height }, { { 0, 31, height + 0 }, { 32, 1, 64 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 0, height + 4, session.SupportColours); + break; + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_DIVE_LOOP + 9)), + { -16, -16, height }, { { 2, 2, height + 4 }, { 28, 28, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 0, height + 4, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_DIVE_LOOP + 13)), + { -16, -16, height }, { { 2, 2, height + 12 }, { 28, 28, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 0, height + 4, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::topCorner, + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 112); + break; + case 4: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_DIVE_LOOP + 2)), + { -16, -16, height }, { { 0, 31, height + 0 }, { 32, 1, 64 } }); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_DIVE_LOOP + 6)), + { -16, -16, height }, { { 0, 31, height + 0 }, { 32, 1, 64 } }); + break; + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_DIVE_LOOP + 10)), + { -16, -16, height }, { { 0, 0, height + 0 }, { 32, 1, 64 } }); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_DIVE_LOOP + 14)), + { -16, -16, height }, { { 0, 6, height + 58 }, { 32, 20, 1 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::topCorner, + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 80); + break; + case 5: + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::topCorner, + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_DIVE_LOOP + 3)), + { -16, -16, height }, { { 0, 6, height + 32 }, { 32, 20, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomLeftSide, 0, height + 41, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_DIVE_LOOP + 7)), + { -16, -16, height }, { { 0, 6, height + 32 }, { 32, 20, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopLeftSide, 0, height + 41, session.SupportColours); + break; + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_DIVE_LOOP + 11)), + { -16, -16, height }, { { 0, 6, height + 32 }, { 32, 20, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopRightSide, 0, height + 41, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_DIVE_LOOP + 15)), + { -16, -16, height }, { { 0, 6, height + 32 }, { 32, 20, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomRightSide, 0, height + 41, session.SupportColours); + break; + } + PaintUtilSetGeneralSupportHeight(session, height + 56); + break; + } +} + +static void TwisterRCTrackRightEighthDiveLoopUpToOrthogonal( + PaintSession& session, const Ride& ride, uint8_t trackSequence, uint8_t direction, int32_t height, + const TrackElement& trackElement, SupportType supportType) +{ + switch (trackSequence) + { + case 0: + switch (direction) + { + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_DIVE_LOOP + 20)), + { -16, -16, height }, { { 0, 0, height + 48 }, { 32, 32, 1 } }); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_DIVE_LOOP + 28)), + { -16, -16, height }, { { 0, 0, height + -8 }, { 32, 32, 1 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::centre, PaintSegment::topRightSide, PaintSegment::bottomRightSide, + PaintSegment::rightCorner), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 96); + break; + case 1: + switch (direction) + { + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_DIVE_LOOP + 24)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::bottomLeftSide, PaintSegment::centre, PaintSegment::bottomCorner, + PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 120); + break; + case 2: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_DIVE_LOOP + 16)), + { -16, -16, height }, { { -16, -16, height + 0 }, { 32, 32, 3 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::topLeftSide, PaintSegment::topCorner, PaintSegment::centre, PaintSegment::topRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 120); + break; + case 3: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_DIVE_LOOP + 17)), + { -16, -16, height }, { { 2, 2, height + 4 }, { 28, 28, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::LeftCorner, 0, height + 4, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_DIVE_LOOP + 21)), + { -16, -16, height }, { { 31, 0, height + 0 }, { 1, 32, 64 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopCorner, 0, height + 4, session.SupportColours); + break; + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_DIVE_LOOP + 25)), + { -16, -16, height }, { { 31, 0, height + 0 }, { 1, 32, 64 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::RightCorner, 0, height + 4, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_DIVE_LOOP + 29)), + { -16, -16, height }, { { 2, 2, height + 12 }, { 28, 28, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomCorner, 0, height + 4, session.SupportColours); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, PaintSegment::centre, + PaintSegment::bottomCorner, PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 112); + break; + case 4: + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_DIVE_LOOP + 18)), + { -16, -16, height }, { { 0, 0, height + 0 }, { 1, 32, 64 } }); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_DIVE_LOOP + 22)), + { -16, -16, height }, { { 31, 0, height + 0 }, { 1, 32, 64 } }); + break; + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_DIVE_LOOP + 26)), + { -16, -16, height }, { { 31, 0, height + 0 }, { 1, 32, 64 } }); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_DIVE_LOOP + 30)), + { -16, -16, height }, { { 6, 0, height + 58 }, { 20, 32, 1 } }); + break; + } + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, PaintSegment::centre, + PaintSegment::bottomCorner, PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + PaintUtilSetGeneralSupportHeight(session, height + 80); + break; + case 5: + PaintUtilSetSegmentSupportHeight( + session, + PaintUtilRotateSegments( + EnumsToFlags( + PaintSegment::leftCorner, PaintSegment::topLeftSide, PaintSegment::bottomLeftSide, PaintSegment::centre, + PaintSegment::bottomCorner, PaintSegment::bottomRightSide), + direction), + 0xFFFF, 0); + switch (direction) + { + case 0: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_DIVE_LOOP + 19)), + { -16, -16, height }, { { 6, 0, height + 32 }, { 20, 32, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopLeftSide, 0, height + 41, session.SupportColours); + break; + case 1: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_DIVE_LOOP + 23)), + { -16, -16, height }, { { 6, 0, height + 32 }, { 20, 32, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::TopRightSide, 0, height + 41, session.SupportColours); + break; + case 2: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_DIVE_LOOP + 27)), + { -16, -16, height }, { { 6, 0, height + 32 }, { 20, 32, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomRightSide, 0, height + 41, session.SupportColours); + break; + case 3: + PaintAddImageAsParentRotated( + session, direction, session.TrackColours.WithIndex((SPR_G2_BM_TRACK_DIVE_LOOP + 31)), + { -16, -16, height }, { { 6, 0, height + 32 }, { 20, 32, 1 } }); + MetalASupportsPaintSetup( + session, supportType.metal, MetalSupportPlace::BottomLeftSide, 0, height + 41, session.SupportColours); + break; + } + PaintUtilSetGeneralSupportHeight(session, height + 56); + break; + } +} + +static void TwisterRCTrackLeftEighthDiveLoopDownToDiag( + PaintSession& session, const Ride& ride, uint8_t trackSequence, uint8_t direction, int32_t height, + const TrackElement& trackElement, SupportType supportType) +{ + TwisterRCTrackRightEighthDiveLoopUpToOrthogonal( + session, ride, 5 - trackSequence, (direction + 1) & 3, height, trackElement, supportType); +} + +static void TwisterRCTrackRightEighthDiveLoopToDownOrthogonal( + PaintSession& session, const Ride& ride, uint8_t trackSequence, uint8_t direction, int32_t height, + const TrackElement& trackElement, SupportType supportType) +{ + TwisterRCTrackLeftEighthDiveLoopUpToOrthogonal( + session, ride, 5 - trackSequence, (direction + 2) & 3, height, trackElement, supportType); +} + TrackPaintFunction GetTrackPaintFunctionTwisterRC(OpenRCT2::TrackElemType trackType) { switch (trackType) @@ -19530,6 +20898,26 @@ TrackPaintFunction GetTrackPaintFunctionTwisterRC(OpenRCT2::TrackElemType trackT case TrackElemType::RightLargeZeroGRollDown: return TwisterRCTrackRightLargeZeroGRollDown; + // Diagonal flat to steep + case TrackElemType::DiagFlatToUp60LongBase: + return TwisterRCTrackDiagFlatTo60DegUpLongBase; + case TrackElemType::DiagUp60ToFlatLongBase: + return TwisterRCTrackDiag60DegUpToFlatLongBase; + case TrackElemType::DiagFlatToDown60LongBase: + return TwisterRCTrackDiagFlatTo60DegDownLongBase; + case TrackElemType::DiagDown60ToFlatLongBase: + return TwisterRCTrackDiag60DegDownToFlatLongBase; + case TrackElemType::LeftEighthDiveLoopUpToOrthogonal: + return TwisterRCTrackLeftEighthDiveLoopUpToOrthogonal; + + // Dive loops + case TrackElemType::RightEighthDiveLoopUpToOrthogonal: + return TwisterRCTrackRightEighthDiveLoopUpToOrthogonal; + case TrackElemType::LeftEighthDiveLoopDownToDiag: + return TwisterRCTrackLeftEighthDiveLoopDownToDiag; + case TrackElemType::RightEighthDiveLoopDownToDiag: + return TwisterRCTrackRightEighthDiveLoopToDownOrthogonal; + default: return TrackPaintFunctionDummy; } diff --git a/src/openrct2/paint/vehicle/VehiclePaint.cpp b/src/openrct2/paint/vehicle/VehiclePaint.cpp index 88a760bb3a..953b8da286 100644 --- a/src/openrct2/paint/vehicle/VehiclePaint.cpp +++ b/src/openrct2/paint/vehicle/VehiclePaint.cpp @@ -2018,6 +2018,37 @@ static void VehiclePitchUp42BankedRight90( } } +static void VehiclePitchUp42BankedLeft135( + PaintSession& session, const Vehicle* vehicle, int32_t imageDirection, int32_t z, const CarEntry* carEntry) +{ + if (carEntry->GroupEnabled(SpriteGroupType::Corkscrews)) + { + imageDirection = (imageDirection + 8) % 32; + int32_t boundingBoxNum = YawTo4(imageDirection) + 13 * 4 + 144; + int32_t spriteNum = carEntry->SpriteOffset(SpriteGroupType::Corkscrews, imageDirection, 13); + VehicleSpritePaintWithSwinging(session, vehicle, spriteNum, boundingBoxNum, z, carEntry); + } + else + { + VehiclePitchUp42Unbanked(session, vehicle, imageDirection, z, carEntry); + } +} + +static void VehiclePitchUp42BankedRight135( + PaintSession& session, const Vehicle* vehicle, int32_t imageDirection, int32_t z, const CarEntry* carEntry) +{ + if (carEntry->GroupEnabled(SpriteGroupType::Corkscrews)) + { + int32_t boundingBoxNum = YawTo4(imageDirection) + 3 * 4 + 144; + int32_t spriteNum = carEntry->SpriteOffset(SpriteGroupType::Corkscrews, imageDirection, 3); + VehicleSpritePaintWithSwinging(session, vehicle, spriteNum, boundingBoxNum, z, carEntry); + } + else + { + VehiclePitchUp42Unbanked(session, vehicle, imageDirection, z, carEntry); + } +} + // 6D49DC static void VehiclePitchUp42( PaintSession& session, const Vehicle* vehicle, int32_t imageDirection, int32_t z, const CarEntry* carEntry) @@ -2045,12 +2076,18 @@ static void VehiclePitchUp42( case 6: VehiclePitchUp42BankedLeft90(session, vehicle, imageDirection, z, carEntry); break; + case 8: + VehiclePitchUp42BankedLeft135(session, vehicle, imageDirection, z, carEntry); + break; case 10: VehiclePitchUp42BankedRight67(session, vehicle, imageDirection, z, carEntry); break; case 11: VehiclePitchUp42BankedRight90(session, vehicle, imageDirection, z, carEntry); break; + case 13: + VehiclePitchUp42BankedRight135(session, vehicle, imageDirection, z, carEntry); + break; default: VehiclePitchUp42Unbanked(session, vehicle, imageDirection, z, carEntry); } @@ -2736,6 +2773,37 @@ static void VehiclePitchDown42BankedRight90( } } +static void VehiclePitchDown42BankedLeft135( + PaintSession& session, const Vehicle* vehicle, int32_t imageDirection, int32_t z, const CarEntry* carEntry) +{ + if (carEntry->GroupEnabled(SpriteGroupType::Corkscrews)) + { + int32_t boundingBoxNum = YawTo4(imageDirection) + 8 * 4 + 144; + int32_t spriteNum = carEntry->SpriteOffset(SpriteGroupType::Corkscrews, imageDirection, 8); + VehicleSpritePaintWithSwinging(session, vehicle, spriteNum, boundingBoxNum, z, carEntry); + } + else + { + VehiclePitchDown42Unbanked(session, vehicle, imageDirection, z, carEntry); + } +} + +static void VehiclePitchDown42BankedRight135( + PaintSession& session, const Vehicle* vehicle, int32_t imageDirection, int32_t z, const CarEntry* carEntry) +{ + if (carEntry->GroupEnabled(SpriteGroupType::Corkscrews)) + { + imageDirection = (imageDirection + 8) % 32; + int32_t boundingBoxNum = YawTo4(imageDirection) + 18 * 4 + 144; + int32_t spriteNum = carEntry->SpriteOffset(SpriteGroupType::Corkscrews, imageDirection, 18); + VehicleSpritePaintWithSwinging(session, vehicle, spriteNum, boundingBoxNum, z, carEntry); + } + else + { + VehiclePitchDown42Unbanked(session, vehicle, imageDirection, z, carEntry); + } +} + static void VehiclePitchDown42( PaintSession& session, const Vehicle* vehicle, int32_t imageDirection, int32_t z, const CarEntry* carEntry) { @@ -2762,12 +2830,18 @@ static void VehiclePitchDown42( case 6: VehiclePitchDown42BankedLeft90(session, vehicle, imageDirection, z, carEntry); break; + case 8: + VehiclePitchDown42BankedLeft135(session, vehicle, imageDirection, z, carEntry); + break; case 10: VehiclePitchDown42BankedRight67(session, vehicle, imageDirection, z, carEntry); break; case 11: VehiclePitchDown42BankedRight90(session, vehicle, imageDirection, z, carEntry); break; + case 13: + VehiclePitchDown42BankedRight135(session, vehicle, imageDirection, z, carEntry); + break; default: VehiclePitchDown42Unbanked(session, vehicle, imageDirection, z, carEntry); } @@ -3384,7 +3458,7 @@ static void VehiclePitchUp16( #pragma region SlopeUp50 // 6D4E8F -static void VehiclePitchUp50( +static void VehiclePitchUp50Unbanked( PaintSession& session, const Vehicle* vehicle, int32_t imageDirection, int32_t z, const CarEntry* carEntry) { if (carEntry->GroupEnabled(SpriteGroupType::Slopes50)) @@ -3399,6 +3473,127 @@ static void VehiclePitchUp50( } } +static void VehiclePitchUp50BankedLeft45( + PaintSession& session, const Vehicle* vehicle, int32_t imageDirection, int32_t z, const CarEntry* carEntry) +{ + if (carEntry->GroupEnabled(SpriteGroupType::Slopes50Banked45)) + { + int32_t boundingBoxNum = (YawTo16(imageDirection)) + 40; + int32_t spriteNum = carEntry->SpriteOffset(SpriteGroupType::Slopes50Banked45, imageDirection, 0); + VehicleSpritePaintWithSwinging(session, vehicle, spriteNum, boundingBoxNum, z, carEntry); + } + else + { + VehiclePitchUp60Unbanked(session, vehicle, imageDirection, z, carEntry); + } +} + +static void VehiclePitchUp50BankedRight45( + PaintSession& session, const Vehicle* vehicle, int32_t imageDirection, int32_t z, const CarEntry* carEntry) +{ + if (carEntry->GroupEnabled(SpriteGroupType::Slopes50Banked45)) + { + int32_t boundingBoxNum = (YawTo16(imageDirection)) + 40; + int32_t spriteNum = carEntry->SpriteOffset(SpriteGroupType::Slopes50Banked45, imageDirection, 1); + VehicleSpritePaintWithSwinging(session, vehicle, spriteNum, boundingBoxNum, z, carEntry); + } + else + { + VehiclePitchUp60Unbanked(session, vehicle, imageDirection, z, carEntry); + } +} + +static void VehiclePitchUp50BankedLeft67( + PaintSession& session, const Vehicle* vehicle, int32_t imageDirection, int32_t z, const CarEntry* carEntry) +{ + if (carEntry->GroupEnabled(SpriteGroupType::Slopes50Banked67)) + { + int32_t boundingBoxNum = (YawTo16(imageDirection)) + 40; + int32_t spriteNum = carEntry->SpriteOffset(SpriteGroupType::Slopes50Banked67, imageDirection, 0); + VehicleSpritePaintWithSwinging(session, vehicle, spriteNum, boundingBoxNum, z, carEntry); + } + else + { + VehiclePitchUp60Unbanked(session, vehicle, imageDirection, z, carEntry); + } +} + +static void VehiclePitchUp50BankedRight67( + PaintSession& session, const Vehicle* vehicle, int32_t imageDirection, int32_t z, const CarEntry* carEntry) +{ + if (carEntry->GroupEnabled(SpriteGroupType::Slopes50Banked67)) + { + int32_t boundingBoxNum = (YawTo16(imageDirection)) + 40; + int32_t spriteNum = carEntry->SpriteOffset(SpriteGroupType::Slopes50Banked67, imageDirection, 1); + VehicleSpritePaintWithSwinging(session, vehicle, spriteNum, boundingBoxNum, z, carEntry); + } + else + { + VehiclePitchUp60Unbanked(session, vehicle, imageDirection, z, carEntry); + } +} + +static void VehiclePitchUp50BankedLeft90( + PaintSession& session, const Vehicle* vehicle, int32_t imageDirection, int32_t z, const CarEntry* carEntry) +{ + if (carEntry->GroupEnabled(SpriteGroupType::Slopes50Banked90)) + { + int32_t boundingBoxNum = (YawTo16(imageDirection)) + 40; + int32_t spriteNum = carEntry->SpriteOffset(SpriteGroupType::Slopes50Banked90, imageDirection, 0); + VehicleSpritePaintWithSwinging(session, vehicle, spriteNum, boundingBoxNum, z, carEntry); + } + else + { + VehiclePitchUp60Unbanked(session, vehicle, imageDirection, z, carEntry); + } +} + +static void VehiclePitchUp50BankedRight90( + PaintSession& session, const Vehicle* vehicle, int32_t imageDirection, int32_t z, const CarEntry* carEntry) +{ + if (carEntry->GroupEnabled(SpriteGroupType::Slopes50Banked90)) + { + int32_t boundingBoxNum = (YawTo16(imageDirection)) + 40; + int32_t spriteNum = carEntry->SpriteOffset(SpriteGroupType::Slopes50Banked90, imageDirection, 1); + VehicleSpritePaintWithSwinging(session, vehicle, spriteNum, boundingBoxNum, z, carEntry); + } + else + { + VehiclePitchUp60Unbanked(session, vehicle, imageDirection, z, carEntry); + } +} + +static void VehiclePitchUp50( + PaintSession& session, const Vehicle* vehicle, int32_t imageDirection, int32_t z, const CarEntry* carEntry) +{ + switch (GetPaintBankRotation(vehicle)) + { + case 0: + VehiclePitchUp50Unbanked(session, vehicle, imageDirection, z, carEntry); + break; + case 2: + VehiclePitchUp50BankedLeft45(session, vehicle, imageDirection, z, carEntry); + break; + case 4: + VehiclePitchUp50BankedRight45(session, vehicle, imageDirection, z, carEntry); + break; + case 5: + VehiclePitchUp50BankedLeft67(session, vehicle, imageDirection, z, carEntry); + break; + case 6: + VehiclePitchUp50BankedLeft90(session, vehicle, imageDirection, z, carEntry); + break; + case 10: + VehiclePitchUp50BankedRight67(session, vehicle, imageDirection, z, carEntry); + break; + case 11: + VehiclePitchUp50BankedRight90(session, vehicle, imageDirection, z, carEntry); + break; + default: + VehiclePitchUp50Unbanked(session, vehicle, imageDirection, z, carEntry); + } +} + #pragma endregion #pragma endregion @@ -3626,7 +3821,7 @@ static void VehiclePitchDown16( #pragma region SlopeDown50 // 6D4EB8 -static void VehiclePitchDown50( +static void VehiclePitchDown50Unbanked( PaintSession& session, const Vehicle* vehicle, int32_t imageDirection, int32_t z, const CarEntry* carEntry) { if (carEntry->GroupEnabled(SpriteGroupType::Slopes50)) @@ -3641,6 +3836,163 @@ static void VehiclePitchDown50( } } +static void VehiclePitchDown50BankedLeft45( + PaintSession& session, const Vehicle* vehicle, int32_t imageDirection, int32_t z, const CarEntry* carEntry) +{ + if (carEntry->GroupEnabled(SpriteGroupType::Slopes50Banked45)) + { + int32_t boundingBoxNum = (YawTo16(imageDirection)) + 40; + int32_t spriteNum = carEntry->SpriteOffset(SpriteGroupType::Slopes50Banked45, imageDirection, 2); + VehicleSpritePaintWithSwinging(session, vehicle, spriteNum, boundingBoxNum, z, carEntry); + } + else + { + VehiclePitchDown50Unbanked(session, vehicle, imageDirection, z, carEntry); + } +} + +static void VehiclePitchDown50BankedRight45( + PaintSession& session, const Vehicle* vehicle, int32_t imageDirection, int32_t z, const CarEntry* carEntry) +{ + if (carEntry->GroupEnabled(SpriteGroupType::Slopes50Banked45)) + { + int32_t boundingBoxNum = (YawTo16(imageDirection)) + 40; + int32_t spriteNum = carEntry->SpriteOffset(SpriteGroupType::Slopes50Banked45, imageDirection, 3); + VehicleSpritePaintWithSwinging(session, vehicle, spriteNum, boundingBoxNum, z, carEntry); + } + else + { + VehiclePitchDown50Unbanked(session, vehicle, imageDirection, z, carEntry); + } +} + +static void VehiclePitchDown50BankedLeft67( + PaintSession& session, const Vehicle* vehicle, int32_t imageDirection, int32_t z, const CarEntry* carEntry) +{ + if (carEntry->GroupEnabled(SpriteGroupType::Slopes50Banked67)) + { + int32_t boundingBoxNum = (YawTo16(imageDirection)) + 40; + int32_t spriteNum = carEntry->SpriteOffset(SpriteGroupType::Slopes50Banked67, imageDirection, 2); + VehicleSpritePaintWithSwinging(session, vehicle, spriteNum, boundingBoxNum, z, carEntry); + } + else + { + VehiclePitchDown50Unbanked(session, vehicle, imageDirection, z, carEntry); + } +} + +static void VehiclePitchDown50BankedRight67( + PaintSession& session, const Vehicle* vehicle, int32_t imageDirection, int32_t z, const CarEntry* carEntry) +{ + if (carEntry->GroupEnabled(SpriteGroupType::Slopes50Banked67)) + { + int32_t boundingBoxNum = (YawTo16(imageDirection)) + 40; + int32_t spriteNum = carEntry->SpriteOffset(SpriteGroupType::Slopes50Banked67, imageDirection, 3); + VehicleSpritePaintWithSwinging(session, vehicle, spriteNum, boundingBoxNum, z, carEntry); + } + else + { + VehiclePitchDown50Unbanked(session, vehicle, imageDirection, z, carEntry); + } +} + +static void VehiclePitchDown50BankedLeft90( + PaintSession& session, const Vehicle* vehicle, int32_t imageDirection, int32_t z, const CarEntry* carEntry) +{ + if (carEntry->GroupEnabled(SpriteGroupType::Slopes50Banked90)) + { + int32_t boundingBoxNum = (YawTo16(imageDirection)) + 40; + int32_t spriteNum = carEntry->SpriteOffset(SpriteGroupType::Slopes50Banked90, imageDirection, 2); + VehicleSpritePaintWithSwinging(session, vehicle, spriteNum, boundingBoxNum, z, carEntry); + } + else + { + VehiclePitchDown50Unbanked(session, vehicle, imageDirection, z, carEntry); + } +} + +static void VehiclePitchDown50BankedRight90( + PaintSession& session, const Vehicle* vehicle, int32_t imageDirection, int32_t z, const CarEntry* carEntry) +{ + if (carEntry->GroupEnabled(SpriteGroupType::Slopes50Banked90)) + { + int32_t boundingBoxNum = (YawTo16(imageDirection)) + 40; + int32_t spriteNum = carEntry->SpriteOffset(SpriteGroupType::Slopes50Banked90, imageDirection, 3); + VehicleSpritePaintWithSwinging(session, vehicle, spriteNum, boundingBoxNum, z, carEntry); + } + else + { + VehiclePitchDown50Unbanked(session, vehicle, imageDirection, z, carEntry); + } +} + +static void VehiclePitchDown50BankedLeft135( + PaintSession& session, const Vehicle* vehicle, int32_t imageDirection, int32_t z, const CarEntry* carEntry) +{ + if (carEntry->GroupEnabled(SpriteGroupType::Corkscrews)) + { + int32_t boundingBoxNum = (YawTo4(imageDirection)) + 4 * 4 + 144; + int32_t spriteNum = carEntry->SpriteOffset(SpriteGroupType::Corkscrews, imageDirection, 4); + VehicleSpritePaintWithSwinging(session, vehicle, spriteNum, boundingBoxNum, z, carEntry); + } + else + { + VehiclePitchDown60Unbanked(session, vehicle, imageDirection, z, carEntry); + } +} + +static void VehiclePitchDown50BankedRight135( + PaintSession& session, const Vehicle* vehicle, int32_t imageDirection, int32_t z, const CarEntry* carEntry) +{ + if (carEntry->GroupEnabled(SpriteGroupType::Corkscrews)) + { + int32_t boundingBoxNum = (YawTo4(imageDirection)) + 4 * 4 + 144; + int32_t spriteNum = carEntry->SpriteOffset(SpriteGroupType::Corkscrews, imageDirection, 4); + VehicleSpritePaintWithSwinging(session, vehicle, spriteNum, boundingBoxNum, z, carEntry); + } + else + { + VehiclePitchDown60Unbanked(session, vehicle, imageDirection, z, carEntry); + } +} + +static void VehiclePitchDown50( + PaintSession& session, const Vehicle* vehicle, int32_t imageDirection, int32_t z, const CarEntry* carEntry) +{ + switch (GetPaintBankRotation(vehicle)) + { + case 0: + VehiclePitchDown50Unbanked(session, vehicle, imageDirection, z, carEntry); + break; + case 2: + VehiclePitchDown50BankedLeft45(session, vehicle, imageDirection, z, carEntry); + break; + case 4: + VehiclePitchDown50BankedRight45(session, vehicle, imageDirection, z, carEntry); + break; + case 5: + VehiclePitchDown50BankedLeft67(session, vehicle, imageDirection, z, carEntry); + break; + case 6: + VehiclePitchDown50BankedLeft90(session, vehicle, imageDirection, z, carEntry); + break; + case 8: + VehiclePitchDown50BankedLeft135(session, vehicle, imageDirection, z, carEntry); + break; + case 10: + VehiclePitchDown50BankedRight67(session, vehicle, imageDirection, z, carEntry); + break; + case 11: + VehiclePitchDown50BankedRight90(session, vehicle, imageDirection, z, carEntry); + break; + case 13: + VehiclePitchDown50BankedRight135(session, vehicle, imageDirection, z, carEntry); + break; + default: + VehiclePitchDown60Unbanked(session, vehicle, imageDirection, z, carEntry); + } +} + #pragma endregion #pragma endregion diff --git a/src/openrct2/park/Legacy.cpp b/src/openrct2/park/Legacy.cpp index b955595587..6e6bab6c01 100644 --- a/src/openrct2/park/Legacy.cpp +++ b/src/openrct2/park/Legacy.cpp @@ -2335,6 +2335,21 @@ static bool ConvertPeepAnimationType(TPeepType* peep, AnimObjectConversionTable& auto& conversion = table[legacyPAG]; peep->AnimationObjectIndex = conversion.first; peep->AnimationGroup = static_cast(conversion.second); + + if (!peep->template Is()) + return true; + + // NB: 'EatFood' used to be supported, but turned out to be unused in C++ code. + // Assigned sprites were found to be identical to those of 'Wave2', hence the mapping. + // However, it appears to have been used by JavaScript plugins, still, hence the + // need to convert any existing sprites. + if (peep->AnimationType == PeepAnimationType::EatFood) + peep->AnimationType = PeepAnimationType::Wave2; + + // NB: this is likely unnecessary, but a precautionary measure considering the above. + if (peep->NextAnimationType == PeepAnimationType::EatFood) + peep->NextAnimationType = PeepAnimationType::Wave2; + return true; } diff --git a/src/openrct2/park/ParkFile.h b/src/openrct2/park/ParkFile.h index 31450afea3..e4ed437652 100644 --- a/src/openrct2/park/ParkFile.h +++ b/src/openrct2/park/ParkFile.h @@ -11,10 +11,10 @@ namespace OpenRCT2 struct GameState_t; // Current version that is saved. - constexpr uint32_t PARK_FILE_CURRENT_VERSION = 49; + constexpr uint32_t PARK_FILE_CURRENT_VERSION = 50; // The minimum version that is forwards compatible with the current version. - constexpr uint32_t PARK_FILE_MIN_VERSION = 49; + constexpr uint32_t PARK_FILE_MIN_VERSION = 50; // The minimum version that is backwards compatible with the current version. // If this is increased beyond 0, uncomment the checks in ParkFile.cpp and Context.cpp! @@ -38,6 +38,7 @@ namespace OpenRCT2 constexpr uint16_t kParkEntranceObjectLimitIncreased = 47; constexpr uint16_t kExtendedStandUpRollerCoasterVersion = 48; constexpr uint16_t kPeepAnimationObjectsVersion = 49; + constexpr uint16_t kDiagonalLongFlatToSteepAndDiveLoopVersion = 50; } // namespace OpenRCT2 class ParkFileExporter diff --git a/src/openrct2/ride/CableLift.cpp b/src/openrct2/ride/CableLift.cpp index 7b410a0185..00613a67cd 100644 --- a/src/openrct2/ride/CableLift.cpp +++ b/src/openrct2/ride/CableLift.cpp @@ -327,7 +327,10 @@ bool Vehicle::CableLiftUpdateTrackMotionBackwards() SetTrackDirection(output.begin_direction); SetTrackType(output.begin_element->AsTrack()->GetTrackType()); - if (output.begin_element->AsTrack()->GetTrackType() == TrackElemType::EndStation) + // Doesn't check for diagonal block brakes because there is no diagonal cable lift piece, + // no way for a cable lift to start from a diagonal brake. + if (output.begin_element->AsTrack()->GetTrackType() == TrackElemType::EndStation + || output.begin_element->AsTrack()->GetTrackType() == TrackElemType::BlockBrakes) { _vehicleMotionTrackFlags = VEHICLE_UPDATE_MOTION_TRACK_FLAG_VEHICLE_AT_STATION; } diff --git a/src/openrct2/ride/CarEntry.h b/src/openrct2/ride/CarEntry.h index ea830cff8a..5413825f9c 100644 --- a/src/openrct2/ride/CarEntry.h +++ b/src/openrct2/ride/CarEntry.h @@ -146,6 +146,9 @@ enum class SpriteGroupType : uint8_t Slopes42Banked67, Slopes42Banked90, Slopes60Banked22, + Slopes50Banked45, + Slopes50Banked67, + Slopes50Banked90, Corkscrews, RestraintAnimation, CurvedLiftHillUp, @@ -153,18 +156,26 @@ enum class SpriteGroupType : uint8_t Count }; -static constexpr const char* SpriteGroupNames[] = { - "slopeFlat", "slopes12", "slopes25", "slopes42", - "slopes60", "slopes75", "slopes90", "slopesLoop", - "slopeInverted", "slopes8", "slopes16", "slopes50", - "flatBanked22", "flatBanked45", "flatBanked67", "flatBanked90", - "inlineTwists", "slopes12Banked22", "slopes8Banked22", "slopes25Banked22", - "slopes8Banked45", "slopes16Banked22", "slopes16Banked45", "slopes25Banked45", - "slopes12Banked45", "slopes25Banked67", "slopes25Banked90", "slopes25InlineTwists", - "slopes42Banked22", "slopes42Banked45", "slopes42Banked67", "slopes42Banked90", - "slopes60Banked22", "corkscrews", "restraintAnimation", "curvedLiftHillUp", - "curvedLiftHillDown", -}; +static constexpr const char* SpriteGroupNames[] = { "slopeFlat", "slopes12", + "slopes25", "slopes42", + "slopes60", "slopes75", + "slopes90", "slopesLoop", + "slopeInverted", "slopes8", + "slopes16", "slopes50", + "flatBanked22", "flatBanked45", + "flatBanked67", "flatBanked90", + "inlineTwists", "slopes12Banked22", + "slopes8Banked22", "slopes25Banked22", + "slopes8Banked45", "slopes16Banked22", + "slopes16Banked45", "slopes25Banked45", + "slopes12Banked45", "slopes25Banked67", + "slopes25Banked90", "slopes25InlineTwists", + "slopes42Banked22", "slopes42Banked45", + "slopes42Banked67", "slopes42Banked90", + "slopes60Banked22", "slopes50Banked45", + "slopes50Banked67", "slopes50Banked90", + "corkscrews", "restraintAnimation", + "curvedLiftHillUp", "curvedLiftHillDown" }; static_assert(std::size(SpriteGroupNames) == EnumValue(SpriteGroupType::Count)); struct VehicleSpriteGroup diff --git a/src/openrct2/ride/Ride.cpp b/src/openrct2/ride/Ride.cpp index 796c6d8abc..a376e5443f 100644 --- a/src/openrct2/ride/Ride.cpp +++ b/src/openrct2/ride/Ride.cpp @@ -1046,12 +1046,12 @@ const RideStation& Ride::GetStation(StationIndex stationIndex) const return stations[stationIndex.ToUnderlying()]; } -std::array& Ride::GetStations() +std::span Ride::GetStations() { return stations; } -const std::array& Ride::GetStations() const +std::span Ride::GetStations() const { return stations; } @@ -3561,7 +3561,6 @@ static void RideCreateVehiclesFindFirstBlock(const Ride& ride, CoordsXYE* outXYE } [[fallthrough]]; case TrackElemType::EndStation: - case TrackElemType::CableLiftHill: case TrackElemType::BlockBrakes: *outXYElement = { trackPos, reinterpret_cast(trackElement) }; return; @@ -3681,12 +3680,8 @@ void Ride::MoveTrainsToBlockBrakes(const CoordsXYZ& firstBlockPosition, TrackEle cableLiftTileElement = MapGetTrackElementAt(CableLiftLoc); if (cableLiftTileElement != nullptr) { - cableLiftTileElement = MapGetTrackElementAt(CableLiftLoc); - if (cableLiftTileElement != nullptr) - { - CoordsXYZ location = CableLiftLoc; - cableLiftPreviousBlock = TrackGetPreviousBlock(location, reinterpret_cast(cableLiftTileElement)); - } + CoordsXYZ location = CableLiftLoc; + cableLiftPreviousBlock = TrackGetPreviousBlock(location, reinterpret_cast(cableLiftTileElement)); } } @@ -3762,6 +3757,24 @@ void Ride::MoveTrainsToBlockBrakes(const CoordsXYZ& firstBlockPosition, TrackEle } } +static bool RideGetStationTile(const Ride& ride, CoordsXYE* output) +{ + for (const auto& station : ride.GetStations()) + { + CoordsXYZ trackStart = station.GetStart(); + if (trackStart.IsNull()) + continue; + + TileElement* tileElement = MapGetTrackElementAtOfType(trackStart, TrackElemType::EndStation); + if (tileElement == nullptr) + continue; + + *output = { trackStart.x, trackStart.y, tileElement }; + return true; + } + return false; +} + /** * Checks and initialises the cable lift track returns false if unable to find * appropriate track. @@ -3769,100 +3782,65 @@ void Ride::MoveTrainsToBlockBrakes(const CoordsXYZ& firstBlockPosition, TrackEle */ static ResultWithMessage RideInitialiseCableLiftTrack(const Ride& ride, bool isApplying) { - CoordsXYZ location; - location.SetNull(); - for (const auto& station : ride.GetStations()) - { - location = station.GetStart(); - if (!location.IsNull()) - break; - } + // Despawn existing cable lift tiles + CoordsXYE stationTile; + if (!RideGetStationTile(ride, &stationTile)) + return { false, STR_CABLE_LIFT_HILL_MUST_START_IMMEDIATELY_AFTER_STATION_OR_BLOCK_BRAKE }; - if (location.IsNull()) + if (isApplying) { - return { false, STR_CABLE_LIFT_HILL_MUST_START_IMMEDIATELY_AFTER_STATION }; - } + // In case circuit is incomplete, find the start of the track in order to ensure all tiles connected + // to the station are cleared + RideGetStartOfTrack(&stationTile); - bool success = false; - TileElement* tileElement = MapGetFirstElementAt(location); - if (tileElement == nullptr) - return { false }; - do - { - if (tileElement->GetType() != TileElementType::Track) - continue; - if (tileElement->GetBaseZ() != location.z) - continue; - - const auto& ted = GetTrackElementDescriptor(tileElement->AsTrack()->GetTrackType()); - if (!(ted.sequences[0].flags & TRACK_SEQUENCE_FLAG_ORIGIN)) + TrackCircuitIterator it; + TrackCircuitIteratorBegin(&it, stationTile); + while (TrackCircuitIteratorNext(&it)) { - continue; + TileElement* tileElement = it.current.element; + GetTrackElementOriginAndApplyChanges( + { { it.current, tileElement->GetBaseZ() }, tileElement->GetDirection() }, + tileElement->AsTrack()->GetTrackType(), 0, &tileElement, TRACK_ELEMENT_SET_HAS_CABLE_LIFT_FALSE); } - success = true; - break; - } while (!(tileElement++)->IsLastForTile()); + } - if (!success) + // Spawn new cable lift tiles + auto cableLiftTileElement = MapGetTrackElementAt(ride.CableLiftLoc); + CoordsXYE cableLiftCoords = { ride.CableLiftLoc, reinterpret_cast(cableLiftTileElement) }; + if (cableLiftTileElement == nullptr) return { false }; - enum - { - STATE_FIND_CABLE_LIFT, - STATE_FIND_STATION, - STATE_REST_OF_TRACK - }; - int32_t state = STATE_FIND_CABLE_LIFT; - TrackCircuitIterator it; - TrackCircuitIteratorBegin(&it, { location, tileElement }); + TrackCircuitIteratorBegin(&it, cableLiftCoords); while (TrackCircuitIteratorPrevious(&it)) { - tileElement = it.current.element; + TileElement* tileElement = it.current.element; auto trackType = tileElement->AsTrack()->GetTrackType(); - - uint16_t flags = TRACK_ELEMENT_SET_HAS_CABLE_LIFT_FALSE; - switch (state) + switch (trackType) { - case STATE_FIND_CABLE_LIFT: - // Search for a cable lift hill track element - if (trackType == TrackElemType::CableLiftHill) + case TrackElemType::Up25: + case TrackElemType::Up60: + case TrackElemType::FlatToUp25: + case TrackElemType::Up25ToFlat: + case TrackElemType::Up25ToUp60: + case TrackElemType::Up60ToUp25: + case TrackElemType::FlatToUp60LongBase: + case TrackElemType::Flat: + if (isApplying) { - flags = TRACK_ELEMENT_SET_HAS_CABLE_LIFT_TRUE; - state = STATE_FIND_STATION; + GetTrackElementOriginAndApplyChanges( + { { it.current, tileElement->GetBaseZ() }, tileElement->GetDirection() }, trackType, 0, &tileElement, + TRACK_ELEMENT_SET_HAS_CABLE_LIFT_TRUE); } break; - case STATE_FIND_STATION: - // Search for the start of the hill - switch (trackType) - { - case TrackElemType::Flat: - case TrackElemType::Up25: - case TrackElemType::Up60: - case TrackElemType::FlatToUp25: - case TrackElemType::Up25ToFlat: - case TrackElemType::Up25ToUp60: - case TrackElemType::Up60ToUp25: - case TrackElemType::FlatToUp60LongBase: - flags = TRACK_ELEMENT_SET_HAS_CABLE_LIFT_TRUE; - break; - case TrackElemType::EndStation: - state = STATE_REST_OF_TRACK; - break; - default: - return { false, STR_CABLE_LIFT_HILL_MUST_START_IMMEDIATELY_AFTER_STATION }; - } - break; - } - if (isApplying) - { - auto tmpLoc = CoordsXYZ{ it.current, tileElement->GetBaseZ() }; - auto direction = tileElement->GetDirection(); - trackType = tileElement->AsTrack()->GetTrackType(); - GetTrackElementOriginAndApplyChanges({ tmpLoc, direction }, trackType, 0, &tileElement, flags); + case TrackElemType::EndStation: + case TrackElemType::BlockBrakes: + return { true }; + default: + return { false, STR_CABLE_LIFT_HILL_MUST_START_IMMEDIATELY_AFTER_STATION_OR_BLOCK_BRAKE }; } } - return { true }; + return { false, STR_CABLE_LIFT_HILL_MUST_START_IMMEDIATELY_AFTER_STATION_OR_BLOCK_BRAKE }; } /** @@ -4791,7 +4769,7 @@ struct NecessarySpriteGroup OpenRCT2::BitSet RideEntryGetSupportedTrackPieces(const RideObjectEntry& rideEntry) { // TODO: Use a std::span when C++20 available as 6 is due to jagged array - static const std::array trackPieceRequiredSprites[] = { + static const std::array trackPieceRequiredSprites[] = { { SpriteGroupType::SlopeFlat, SpritePrecision::None }, // TrackGroup::flat { SpriteGroupType::SlopeFlat, SpritePrecision::Sprites4 }, // TrackGroup::straight { SpriteGroupType::SlopeFlat, SpritePrecision::Sprites4 }, // TrackGroup::stationEnd @@ -4946,7 +4924,17 @@ OpenRCT2::BitSet RideEntryGetSupportedTrackPieces( { SpriteGroupType::SlopeFlat, SpritePrecision::Sprites8 }, // TrackGroup::diagBlockBrakes { SpriteGroupType::Slopes25, SpritePrecision::Sprites4 }, // TrackGroup::inclinedBrakes { SpriteGroupType::SlopeFlat, SpritePrecision::Sprites8 }, // TrackGroup::diagBooster + { SpriteGroupType::Slopes8, SpritePrecision::Sprites4, SpriteGroupType::Slopes16, SpritePrecision::Sprites4, + SpriteGroupType::Slopes25, SpritePrecision::Sprites8, SpriteGroupType::Slopes42, SpritePrecision::Sprites8, + SpriteGroupType::Slopes50, SpritePrecision::Sprites4 }, // TrackGroup::slopeSteepLong + { SpriteGroupType::Slopes50, SpritePrecision::Sprites4, SpriteGroupType::Slopes60Banked22, SpritePrecision::Sprites8, + SpriteGroupType::Slopes50Banked45, SpritePrecision::Sprites8, SpriteGroupType::Slopes50Banked67, + SpritePrecision::Sprites8, SpriteGroupType::Slopes50Banked90, SpritePrecision::Sprites8, SpriteGroupType::Corkscrews, + SpritePrecision::Sprites4, SpriteGroupType::Slopes25InlineTwists, SpritePrecision::Sprites4, + SpriteGroupType::SlopesLoop, SpritePrecision::Sprites4, SpriteGroupType::SlopeInverted, + SpritePrecision::Sprites4 }, // TrackGroup::diveLoop }; + static_assert(std::size(trackPieceRequiredSprites) == EnumValue(TrackGroup::count)); // Only check default vehicle; it's assumed the others will have correct sprites if this one does (I've yet to find an diff --git a/src/openrct2/ride/Ride.h b/src/openrct2/ride/Ride.h index 3db9ed6e76..36b302156b 100644 --- a/src/openrct2/ride/Ride.h +++ b/src/openrct2/ride/Ride.h @@ -28,6 +28,7 @@ #include #include #include +#include #include struct IObjectManager; @@ -293,8 +294,8 @@ private: public: RideStation& GetStation(StationIndex stationIndex = StationIndex::FromUnderlying(0)); const RideStation& GetStation(StationIndex stationIndex = StationIndex::FromUnderlying(0)) const; - std::array& GetStations(); - const std::array& GetStations() const; + std::span GetStations(); + std::span GetStations() const; StationIndex GetStationIndex(const RideStation* station) const; // Returns the logical station number from the given station. Index 0 = station 1, index 1 = station 2. It accounts for gaps diff --git a/src/openrct2/ride/RideData.cpp b/src/openrct2/ride/RideData.cpp index 388e0c1b3e..e1b828e58a 100644 --- a/src/openrct2/ride/RideData.cpp +++ b/src/openrct2/ride/RideData.cpp @@ -176,6 +176,9 @@ const CarEntry CableLiftVehicle = { /* SpriteGroupType::Slopes42Banked67 */ { 0, SpritePrecision::None}, /* SpriteGroupType::Slopes42Banked90 */ { 0, SpritePrecision::None}, /* SpriteGroupType::Slopes60Banked22 */ { 0, SpritePrecision::None}, + /* SpriteGroupType::Slopes60Banked45 */ { 0, SpritePrecision::None}, + /* SpriteGroupType::Slopes60Banked67 */ { 0, SpritePrecision::None}, + /* SpriteGroupType::Slopes60Banked90 */ { 0, SpritePrecision::None}, /* SpriteGroupType::Corkscrews */ { 0, SpritePrecision::None}, /* SpriteGroupType::RestraintAnimation */ { 0, SpritePrecision::None}, /* SpriteGroupType::CurvedLiftHillUp */ { 0, SpritePrecision::None}, diff --git a/src/openrct2/ride/Track.h b/src/openrct2/ride/Track.h index 1ca131e13d..7efff55289 100644 --- a/src/openrct2/ride/Track.h +++ b/src/openrct2/ride/Track.h @@ -148,6 +148,9 @@ enum class TrackGroup : uint8_t inclinedBrakes, diagBooster, + diagSlopeSteepLong, + diveLoop, + count, }; @@ -603,7 +606,17 @@ namespace OpenRCT2 Down25Brakes = 339, DiagBooster = 340, - Count = 341, + DiagFlatToUp60LongBase = 341, + DiagUp60ToFlatLongBase = 342, + DiagFlatToDown60LongBase = 343, + DiagDown60ToFlatLongBase = 344, + LeftEighthDiveLoopUpToOrthogonal = 345, + RightEighthDiveLoopUpToOrthogonal = 346, + LeftEighthDiveLoopDownToDiag = 347, + RightEighthDiveLoopDownToDiag = 348, + + Count = 349, + None = 65535, }; } diff --git a/src/openrct2/ride/TrackData.cpp b/src/openrct2/ride/TrackData.cpp index 0743101054..a20fd4d171 100644 --- a/src/openrct2/ride/TrackData.cpp +++ b/src/openrct2/ride/TrackData.cpp @@ -358,18 +358,26 @@ namespace OpenRCT2::TrackMetaData { 4, 4, 0, 16, -32, 32 }, // TrackElemType::DiagUp25RightBanked { 4, 4, 16, 0, -32, 32 }, // TrackElemType::DiagDown25LeftBanked { 4, 4, 16, 0, -32, 32 }, // TrackElemType::DiagDown25RightBanked - { 0, 7, 0, 48, -64, -32 }, // TrackElemType::LeftEighthBankToDiagUp25 - { 0, 4, 0, 48, -64, 32 }, // TrackElemType::RightEighthBankToDiagUp25 - { 0, 7, 0,-48, -64, -32 }, // TrackElemType::LeftEighthBankToDiagDown25 - { 0, 4, 0,-48, -64, 32 }, // TrackElemType::RightEighthBankToDiagDown25 - { 4, 0, 0, 48, -64, 32 }, // TrackElemType::LeftEighthBankToOrthogonalUp25 - { 4, 1, 0, 48, -32, 64 }, // TrackElemType::RightEighthBankToOrthogonalUp25 - { 4, 0, 0,-48, -64, 32 }, // TrackElemType::LeftEighthBankToOrthogonalDown25 - { 4, 1, 0,-48, -32, 64 }, // TrackElemType::RightEighthBankToOrthogonalDown25 - { 4, 4, 0, 0, -32, 32 }, // TrackElemType::DiagBrakes - { 4, 4, 0, 0, -32, 32 }, // TrackElemType::DiagBlockBrakes - { 0, 0, 16, 0, 0, 0 }, // TrackElemType::Down25Brakes - { 4, 4, 0, 0, -32, 32 }, // TrackElemType::DiagBooster + { 0, 7, 0, 48, -64, -32 }, // TrackElemType::LeftEighthBankToDiagUp25 + { 0, 4, 0, 48, -64, 32 }, // TrackElemType::RightEighthBankToDiagUp25 + { 0, 7, 0,-48, -64, -32 }, // TrackElemType::LeftEighthBankToDiagDown25 + { 0, 4, 0,-48, -64, 32 }, // TrackElemType::RightEighthBankToDiagDown25 + { 4, 0, 0, 48, -64, 32 }, // TrackElemType::LeftEighthBankToOrthogonalUp25 + { 4, 1, 0, 48, -32, 64 }, // TrackElemType::RightEighthBankToOrthogonalUp25 + { 4, 0, 0,-48, -64, 32 }, // TrackElemType::LeftEighthBankToOrthogonalDown25 + { 4, 1, 0,-48, -32, 64 }, // TrackElemType::RightEighthBankToOrthogonalDown25 + { 4, 4, 0, 0, -32, 32 }, // TrackElemType::DiagBrakes + { 4, 4, 0, 0, -32, 32 }, // TrackElemType::DiagBlockBrakes + { 0, 0, 16, 0, 0, 0 }, // TrackElemType::Down25Brakes + { 4, 4, 0, 0, -32, 32 }, // TrackElemType::DiagBooster + { 4, 4, 0, 88, -96, 96 }, // TrackElemType::DiagFlatToUp60LongBase, + { 4, 4, 0, 88, -96, 96 }, // TrackElemType::DiagUp60ToFlatLongBase, + { 4, 4, 88, 0, -96, 96 }, // TrackElemType::DiagFlatToDown60LongBase, + { 4, 4, 88, 0, -96, 96 }, // TrackElemType::DiagDown60ToFlatLongBase, + { 4, 0, 0,152, -96, 32 }, // TrackElemType::LeftEighthDiveLoopUpToOrthogonal + { 4, 1, 0,152, -32, 96 }, // TrackElemType::RightEighthDiveLoopUpToOrthogonal + { 0, 7,152, 0, -96, -32 }, // TrackElemType::LeftEighthDiveLoopDownToDiag + { 0, 4,152, 0, -96, 32 }, // TrackElemType::RightEighthDiveLoopDownToDiag }; static_assert(std::size(_trackCoordinates) == EnumValue(TrackElemType::Count)); @@ -715,7 +723,16 @@ namespace OpenRCT2::TrackMetaData 45, // TrackElemType::DiagBlockBrakes 33, // TrackElemType::Down25Brakes 45, // TrackElemType::DiagBooster + 165, // TrackElemType::DiagFlatToUp60LongBase, + 165, // TrackElemType::DiagUp60ToFlatLongBase, + 165, // TrackElemType::DiagFlatToDown60LongBase, + 165, // TrackElemType::DiagDown60ToFlatLongBase, + 165, // TrackElemType::LeftEighthDiveLoopUpToOrthogonal + 165, // TrackElemType::RightEighthDiveLoopUpToOrthogonal + 165, // TrackElemType::LeftEighthDiveLoopDownToDiag + 165, // TrackElemType::RightEighthDiveLoopDownToDiag }; + static_assert(std::size(TrackPieceLengths) == EnumValue(TrackElemType::Count)); // rct2: 0x00998C95 @@ -1058,9 +1075,17 @@ namespace OpenRCT2::TrackMetaData { TrackCurve::LeftLarge, TrackCurve::LeftLarge }, // TrackElemType::LeftEighthBankToOrthogonalDown25 { TrackCurve::RightLarge, TrackCurve::RightLarge }, // TrackElemType::RightEighthBankToOrthogonalDown25 { TrackElemType::DiagBrakes, TrackElemType::DiagBrakes }, // TrackElemType::DiagBrakes - { TrackCurve::None, TrackCurve::None }, // TrackElemType::DiagBlockBrakes + { TrackCurve::None, TrackCurve::None }, // TrackElemType::DiagBlockBrakes { TrackElemType::Down25Brakes, TrackElemType::Down25Brakes }, // TrackElemType::Down25Brakes { TrackElemType::DiagBooster, TrackElemType::DiagBooster }, // TrackElemType::DiagBooster + { TrackCurve::None, TrackCurve::None }, // TrackElemType::DiagFlatToUp60LongBase, + { TrackCurve::None, TrackCurve::None }, // TrackElemType::DiagUp60ToFlatLongBase, + { TrackCurve::None, TrackCurve::None }, // TrackElemType::DiagFlatToDown60LongBase, + { TrackCurve::None, TrackCurve::None }, // TrackElemType::DiagDown60ToFlatLongBase, + { TrackElemType::RightEighthDiveLoopDownToDiag , TrackCurve::None }, // TrackElemType::LeftEighthDiveLoopUpToOrthogonal + { TrackElemType::LeftEighthDiveLoopDownToDiag, TrackCurve::None }, // TrackElemType::RightEighthDiveLoopUpToOrthogonal + { TrackCurve::None, TrackElemType::RightEighthDiveLoopUpToOrthogonal }, // TrackElemType::LeftEighthDiveLoopDownToDiag + { TrackCurve::None, TrackElemType::LeftEighthDiveLoopUpToOrthogonal }, // TrackElemType::RightEighthDiveLoopDownToDiag }; static_assert(std::size(gTrackCurveChain) == EnumValue(TrackElemType::Count)); @@ -1596,6 +1621,14 @@ namespace OpenRCT2::TrackMetaData TrackElemType::None, // TrackElemType::DiagBlockBrakes TrackElemType::None, // TrackElemType::Down25Brakes TrackElemType::None, // TrackElemType::DiagBooster + TrackElemType::None, // TrackElemType::DiagFlatToUp60LongBase, + TrackElemType::None, // TrackElemType::DiagUp60ToFlatLongBase, + TrackElemType::None, // TrackElemType::DiagFlatToDown60LongBase, + TrackElemType::None, // TrackElemType::DiagDown60ToFlatLongBase, + TrackElemType::None, // TrackElemType::LeftEighthDiveLoopUpToOrthogonal + TrackElemType::None, // TrackElemType::RightEighthDiveLoopUpToOrthogonal + TrackElemType::None, // TrackElemType::LeftEighthDiveLoopDownToDiag + TrackElemType::None, // TrackElemType::RightEighthDiveLoopDownToDiag }; static_assert(std::size(AlternativeTrackTypes) == EnumValue(TrackElemType::Count)); @@ -1942,6 +1975,14 @@ namespace OpenRCT2::TrackMetaData 123456, // TrackElemType::DiagBlockBrakes 109824, // TrackElemType::Down25Brakes 123456, // TrackElemType::DiagBooster + 399690 , // TrackElemType::DiagFlatToUp60LongBase, + 399690, // TrackElemType::DiagUp60ToFlatLongBase, + 399690, // TrackElemType::DiagFlatToDown60LongBase, + 399690, // TrackElemType::DiagDown60ToFlatLongBase, + 458752, // TrackElemType::LeftEighthDiveLoopUpToOrthogonal + 458752, // TrackElemType::RightEighthDiveLoopUpToOrthogonal + 458752, // TrackElemType::LeftEighthDiveLoopDownToDiag + 458752, // TrackElemType::RightEighthDiveLoopDownToDiag }; static_assert(std::size(TrackPricing) == EnumValue(TrackElemType::Count)); @@ -2288,6 +2329,14 @@ namespace OpenRCT2::TrackMetaData TrackElemType::DiagBlockBrakes, TrackElemType::Down25Brakes, TrackElemType::DiagBooster, + TrackElemType::DiagFlatToUp60LongBase, // TrackElemType::DiagFlatToUp60LongBase, + TrackElemType::DiagUp60ToFlatLongBase, // TrackElemType::DiagUp60ToFlatLongBase, + TrackElemType::DiagFlatToDown60LongBase, // TrackElemType::DiagFlatToDown60LongBase, + TrackElemType::DiagDown60ToFlatLongBase, // TrackElemType::DiagDown60ToFlatLongBase, + TrackElemType::RightEighthDiveLoopUpToOrthogonal, // TrackElemType::LeftEighthDiveLoopUpToOrthogonal + TrackElemType::LeftEighthDiveLoopUpToOrthogonal, // TrackElemType::RightEighthDiveLoopUpToOrthogonal + TrackElemType::RightEighthDiveLoopDownToDiag, // TrackElemType::LeftEighthDiveLoopDownToDiag + TrackElemType::LeftEighthDiveLoopDownToDiag, // TrackElemType::RightEighthDiveLoopDownToDiag }; static_assert(std::size(TrackElementMirrorMap) == EnumValue(TrackElemType::Count)); @@ -2634,6 +2683,14 @@ namespace OpenRCT2::TrackMetaData (1 << 0), // TrackElemType::DiagBlockBrakes (1 << 0), // TrackElemType::Down25Brakes (1 << 0), // TrackElemType::DiagBooster + (1 << 0), // TrackElemType::DiagFlatToUp60LongBase, + (1 << 0), // TrackElemType::DiagUp60ToFlatLongBase, + (1 << 9), // TrackElemType::DiagFlatToDown60LongBase, + (1 << 9), // TrackElemType::DiagDown60ToFlatLongBase, + (1 << 0) | (1 << 5), // TrackElemType::LeftEighthDiveLoopUpToOrthogonal + (1 << 0) | (1 << 5), // TrackElemType::RightEighthDiveLoopUpToOrthogonal + (1 << 0) | (1 << 5), // TrackElemType::LeftEighthDiveLoopDownToDiag + (1 << 0) | (1 << 5), // TrackElemType::RightEighthDiveLoopDownToDiag }; static_assert(std::size(TrackHeightMarkerPositions) == EnumValue(TrackElemType::Count)); @@ -2983,6 +3040,14 @@ namespace OpenRCT2::TrackMetaData /* TrackElemType::DiagBlockBrakes */ 0, /* TrackElemType::Down25Brakes */ TRACK_ELEM_FLAG_DOWN | TRACK_ELEM_FLAG_STARTS_AT_HALF_HEIGHT, /* TrackElemType::DiagBooster */ 0, + /* TrackElemType::DiagFlatToUp60LongBase */ TRACK_ELEM_FLAG_UP | TRACK_ELEM_FLAG_IS_STEEP_UP, + /* TrackElemType::DiagUp60ToFlatLongBase */ TRACK_ELEM_FLAG_UP | TRACK_ELEM_FLAG_STARTS_AT_HALF_HEIGHT | TRACK_ELEM_FLAG_IS_STEEP_UP, + /* TrackElemType::DiagFlatToDown60LongBase */ TRACK_ELEM_FLAG_DOWN | TRACK_ELEM_FLAG_STARTS_AT_HALF_HEIGHT, + /* TrackElemType::DiagDown60ToFlatLongBase */ TRACK_ELEM_FLAG_DOWN, + /* TrackElemType::LeftEighthDiveLoopUpToOrthogonal */ TRACK_ELEM_FLAG_UP | TRACK_ELEM_FLAG_STARTS_AT_HALF_HEIGHT | TRACK_ELEM_FLAG_NORMAL_TO_INVERSION | TRACK_ELEM_FLAG_INVERSION_TO_NORMAL, + /* TrackElemType::RightEighthDiveLoopUpToOrthogonal */ TRACK_ELEM_FLAG_UP | TRACK_ELEM_FLAG_STARTS_AT_HALF_HEIGHT | TRACK_ELEM_FLAG_NORMAL_TO_INVERSION | TRACK_ELEM_FLAG_INVERSION_TO_NORMAL, + /* TrackElemType::LeftEighthDiveLoopDownToDiag */ TRACK_ELEM_FLAG_DOWN | TRACK_ELEM_FLAG_STARTS_AT_HALF_HEIGHT | TRACK_ELEM_FLAG_INVERSION_TO_NORMAL, + /* TrackElemType::RightEighthDiveLoopDownToDiag */ TRACK_ELEM_FLAG_DOWN | TRACK_ELEM_FLAG_STARTS_AT_HALF_HEIGHT | TRACK_ELEM_FLAG_INVERSION_TO_NORMAL, }; static_assert(std::size(TrackFlags) == EnumValue(TrackElemType::Count)); // clang-format on @@ -3333,6 +3398,14 @@ namespace OpenRCT2::TrackMetaData { TrackGroup::diagBlockBrakes, TrackPitch::None, TrackPitch::None, TrackRoll::None, TrackRoll::None, 0 }, // TrackElemType::DiagBlockBrakes { TrackGroup::inclinedBrakes, TrackPitch::Down25, TrackPitch::Down25, TrackRoll::None, TrackRoll::None, 0 }, // TrackElemType::Down25Brakes { TrackGroup::diagBooster, TrackPitch::None, TrackPitch::None, TrackRoll::None, TrackRoll::None, 0 }, // TrackElemType::DiagBooster + { TrackGroup::slopeSteepLong, TrackPitch::Up60, TrackPitch::None, TrackRoll::None, TrackRoll::None, 16 }, // TrackElemType::DiagFlatToUp60LongBase, + { TrackGroup::slopeSteepLong, TrackPitch::None, TrackPitch::Up60, TrackRoll::None, TrackRoll::None, 48 }, // TrackElemType::DiagUp60ToFlatLongBase, + { TrackGroup::slopeSteepLong, TrackPitch::Down60, TrackPitch::None, TrackRoll::None, TrackRoll::None, -32 }, // TrackElemType::DiagFlatToDown60LongBase, + { TrackGroup::slopeSteepLong, TrackPitch::None, TrackPitch::Down60, TrackRoll::None, TrackRoll::None, -24 }, // TrackElemType::DiagDown60ToFlatLongBase, + { TrackGroup::diveLoop, TrackPitch::None, TrackPitch::Up60, TrackRoll::UpsideDown, TrackRoll::None, 56 }, // TrackElemType::LeftEighthDiveLoopUpToOrthogonal + { TrackGroup::diveLoop, TrackPitch::None, TrackPitch::Up60, TrackRoll::UpsideDown, TrackRoll::None, 56 }, // TrackElemType::RightEighthDiveLoopUpToOrthogonal + { TrackGroup::diveLoop, TrackPitch::Down60, TrackPitch::None, TrackRoll::None, TrackRoll::UpsideDown, -56 }, // TrackElemType::LeftEighthDiveLoopDownToDiag + { TrackGroup::diveLoop, TrackPitch::Down60, TrackPitch::None, TrackRoll::None, TrackRoll::UpsideDown, -56 }, // TrackElemType::RightEighthDiveLoopDownToDiag }; static_assert(std::size(TrackDefinitions) == EnumValue(TrackElemType::Count)); @@ -3395,7 +3468,9 @@ namespace OpenRCT2::TrackMetaData SpinFunction::None, SpinFunction::None, SpinFunction::None, SpinFunction::None, SpinFunction::None, SpinFunction::None, SpinFunction::None, SpinFunction::None, SpinFunction::None, SpinFunction::None, SpinFunction::None, SpinFunction::L9, SpinFunction::R9, SpinFunction::L9, SpinFunction::R9, SpinFunction::L9, SpinFunction::R9, SpinFunction::L9, - SpinFunction::R9, SpinFunction::None, SpinFunction::None, SpinFunction::None, SpinFunction::None + SpinFunction::R9, SpinFunction::None, SpinFunction::None, SpinFunction::None, SpinFunction::None, SpinFunction::None, + SpinFunction::None, SpinFunction::None, SpinFunction::None, SpinFunction::L9, SpinFunction::R9, SpinFunction::L9, + SpinFunction::R9 }; static_assert(std::size(TrackTypeToSpinFunction) == EnumValue(TrackElemType::Count)); @@ -3474,6 +3549,36 @@ namespace OpenRCT2::TrackMetaData return -(73 + progress); } + static int32_t EvaluatorDiveLoopUp(const int16_t progress) + { + return 385 - 2 * progress; + } + + static int32_t EvaluatorDiveLoopDown(const int16_t progress) + { + return 67 + 2 * progress; + } + + static int32_t EvaluatorDiveLoopUpLeft(const int16_t progress) + { + return 380 - 2 * progress; + } + + static int32_t EvaluatorDiveLoopUpRight(const int16_t progress) + { + return 2 * progress - 380; + } + + static int32_t EvaluatorDiveLoopDownLeft(const int16_t progress) + { + return -(62 + 2 * progress); + } + + static int32_t EvaluatorDiveLoopDownRight(const int16_t progress) + { + return 62 + 2 * progress; + } + static int32_t EvaluatorWaterSplash(const int16_t progress) { if (progress < 32) @@ -3816,9 +3921,13 @@ namespace OpenRCT2::TrackMetaData return EvaluatorConst<0>; case TrackElemType::FlatToUp60LongBase: case TrackElemType::Down60ToFlatLongBase: + case TrackElemType::DiagFlatToUp60LongBase: + case TrackElemType::DiagDown60ToFlatLongBase: return EvaluatorConst<0>; case TrackElemType::Up60ToFlatLongBase: case TrackElemType::FlatToDown60LongBase: + case TrackElemType::DiagUp60ToFlatLongBase: + case TrackElemType::DiagFlatToDown60LongBase: return EvaluatorConst<0>; case TrackElemType::ReverseFreefallSlope: case TrackElemType::AirThrustVerticalDownToLevel: @@ -3905,6 +4014,14 @@ namespace OpenRCT2::TrackMetaData return EvaluatorLargeZeroGRollDownLeft; case TrackElemType::RightLargeZeroGRollDown: return EvaluatorLargeZeroGRollDownRight; + case TrackElemType::LeftEighthDiveLoopUpToOrthogonal: + return EvaluatorDiveLoopUpLeft; + case TrackElemType::RightEighthDiveLoopUpToOrthogonal: + return EvaluatorDiveLoopUpRight; + case TrackElemType::LeftEighthDiveLoopDownToDiag: + return EvaluatorDiveLoopDownLeft; + case TrackElemType::RightEighthDiveLoopDownToDiag: + return EvaluatorDiveLoopDownRight; case TrackElemType::LeftBankToLeftQuarterTurn3TilesUp25: return EvaluatorConst<90>; case TrackElemType::RightBankToRightQuarterTurn3TilesUp25: @@ -4204,6 +4321,12 @@ namespace OpenRCT2::TrackMetaData case TrackElemType::Up60ToFlatLongBase: case TrackElemType::FlatToDown60LongBase: return EvaluatorConst<-160>; + case TrackElemType::DiagFlatToUp60LongBase: + case TrackElemType::DiagDown60ToFlatLongBase: + return EvaluatorConst<180>; + case TrackElemType::DiagUp60ToFlatLongBase: + case TrackElemType::DiagFlatToDown60LongBase: + return EvaluatorConst<-180>; case TrackElemType::ReverseFreefallSlope: case TrackElemType::AirThrustVerticalDownToLevel: return EvaluatorConst<120>; @@ -4293,6 +4416,12 @@ namespace OpenRCT2::TrackMetaData case TrackElemType::LeftLargeZeroGRollDown: case TrackElemType::RightLargeZeroGRollDown: return EvaluatorLargeZeroGRollDown; + case TrackElemType::LeftEighthDiveLoopUpToOrthogonal: + case TrackElemType::RightEighthDiveLoopUpToOrthogonal: + return EvaluatorDiveLoopUp; + case TrackElemType::LeftEighthDiveLoopDownToDiag: + case TrackElemType::RightEighthDiveLoopDownToDiag: + return EvaluatorDiveLoopDown; case TrackElemType::LeftBankToLeftQuarterTurn3TilesUp25: case TrackElemType::RightBankToRightQuarterTurn3TilesUp25: case TrackElemType::LeftQuarterTurn3TilesDown25ToLeftBank: @@ -4691,6 +4820,14 @@ namespace OpenRCT2::TrackMetaData STR_BLOCK_BRAKES, // TrackElemType::DiagBlockBrakes STR_BRAKES, // TrackElemType::Down25Brakes STR_BOOSTER, // TrackElemType::DiagBooster + STR_EMPTY, // TrackElemType::DiagFlatToUp60LongBase, + STR_EMPTY, // TrackElemType::DiagUp60ToFlatLongBase, + STR_EMPTY, // TrackElemType::DiagFlatToDown60LongBase, + STR_EMPTY, // TrackElemType::DiagDown60ToFlatLongBase, + STR_DIVE_LOOP_LEFT, // TrackElemType::LeftEighthDiveLoopUpToOrthogonal + STR_DIVE_LOOP_RIGHT, // TrackElemType::RightEighthDiveLoopUpToOrthogonal + STR_DIVE_LOOP_LEFT, // TrackElemType::LeftEighthDiveLoopDownToDiag + STR_DIVE_LOOP_RIGHT, // TrackElemType::RightEighthDiveLoopDownToDiag }; static_assert(std::size(RideConfigurationStringIds) == EnumValue(TrackElemType::Count)); @@ -11713,6 +11850,263 @@ namespace OpenRCT2::TrackMetaData .clearance = { -32, 32, 0, 0, { 0b0010, 0 }, 0 }, }; + static constexpr SequenceDescriptor kDiagFlatToUp60LongBaseSeq0 = { + .clearance = { 0, 0, 0, 0, { 0b1101, 0 }, 0 }, + .allowedWallEdges = 0b0000, + }; + static constexpr SequenceDescriptor kDiagFlatToUp60LongBaseSeq1 = { + .clearance = { 0, 32, 0, 16, { 0b0100, 0 }, 0 }, + .allowedWallEdges = 0b0110, + }; + static constexpr SequenceDescriptor kDiagFlatToUp60LongBaseSeq2 = { + .clearance = { -32, 0, 0, 16, { 0b0001, 0 }, 0 }, + .allowedWallEdges = 0b1001, + }; + static constexpr SequenceDescriptor kDiagFlatToUp60LongBaseSeq3 = { + .clearance = { -32, 32, 0, 32, { 0b1111, 0 }, 0 }, + .allowedWallEdges = 0b0000, + }; + static constexpr SequenceDescriptor kDiagFlatToUp60LongBaseSeq4 = { + .clearance = { -32, 64, 8, 40, { 0b0100, 0 }, 0 }, + .allowedWallEdges = 0b0110, + }; + static constexpr SequenceDescriptor kDiagFlatToUp60LongBaseSeq5 = { + .clearance = { -64, 32, 8, 40, { 0b0001, 0 }, 0 }, + .allowedWallEdges = 0b1001, + }; + static constexpr SequenceDescriptor kDiagFlatToUp60LongBaseSeq6 = { + .clearance = { -64, 64, 8, 64, { 0b1111, 0 }, 0 }, + .allowedWallEdges = 0b0000, + }; + static constexpr SequenceDescriptor kDiagFlatToUp60LongBaseSeq7 = { + .clearance = { -64, 96, 40, 88, { 0b0100, 0 }, 0 }, + .allowedWallEdges = 0b0110, + }; + static constexpr SequenceDescriptor kDiagFlatToUp60LongBaseSeq8 = { + .clearance = { -96, 64, 40, 88, { 0b0001, 0 }, 0 }, + .allowedWallEdges = 0b1001, + }; + static constexpr SequenceDescriptor kDiagFlatToUp60LongBaseSeq9 = { + .clearance = { -96, 96, 40, 104, { 0b0010, 0 }, 0 }, + .allowedWallEdges = 0b0000, + }; + static constexpr SequenceDescriptor kDiagUp60ToFlatLongBaseSeq0 = { + .clearance = { 0, 0, 0, 64, { 0b1101, 0 }, 0 }, + .allowedWallEdges = 0b0000, + }; + static constexpr SequenceDescriptor kDiagUp60ToFlatLongBaseSeq1 = { + .clearance = { 0, 32, 0, 72, { 0b0100, 0 }, 0 }, + .allowedWallEdges = 0b0110, + }; + static constexpr SequenceDescriptor kDiagUp60ToFlatLongBaseSeq2 = { + .clearance = { -32, 0, 0, 72, { 0b0001, 0 }, 0 }, + .allowedWallEdges = 0b1001, + }; + static constexpr SequenceDescriptor kDiagUp60ToFlatLongBaseSeq3 = { + .clearance = { -32, 32, 0, 80, { 0b1111, 0 }, 0 }, + .allowedWallEdges = 0b0000, + }; + static constexpr SequenceDescriptor kDiagUp60ToFlatLongBaseSeq4 = { + .clearance = { -32, 64, 56, 32, { 0b0100, 0 }, 0 }, + .allowedWallEdges = 0b0110, + }; + static constexpr SequenceDescriptor kDiagUp60ToFlatLongBaseSeq5 = { + .clearance = { -64, 32, 56, 32, { 0b0001, 0 }, 0 }, + .allowedWallEdges = 0b1001, + }; + static constexpr SequenceDescriptor kDiagUp60ToFlatLongBaseSeq6 = { + .clearance = { -64, 64, 56, 8, { 0b1111, 0 }, 0 }, + .allowedWallEdges = 0b0000, + }; + static constexpr SequenceDescriptor kDiagUp60ToFlatLongBaseSeq7 = { + .clearance = { -64, 96, 80, 8, { 0b0100, 0 }, 0 }, + .allowedWallEdges = 0b0110, + }; + static constexpr SequenceDescriptor kDiagUp60ToFlatLongBaseSeq8 = { + .clearance = { -96, 64, 80, 8, { 0b0001, 0 }, 0 }, + .allowedWallEdges = 0b1001, + }; + static constexpr SequenceDescriptor kDiagUp60ToFlatLongBaseSeq9 = { + .clearance = { -96, 96, 80, 8, { 0b0010, 0 }, 0 }, + .allowedWallEdges = 0b0000, + }; + static constexpr SequenceDescriptor kDiagFlatToDown60LongBaseSeq0 = { + .clearance = { 0, 0, 80, 8, { 0b1101, 0 }, 0 }, + .allowedWallEdges = 0b0000, + }; + static constexpr SequenceDescriptor kDiagFlatToDown60LongBaseSeq1 = { + .clearance = { 0, 32, 80, 8, { 0b0100, 0 }, 0 }, + .allowedWallEdges = 0b0110, + }; + static constexpr SequenceDescriptor kDiagFlatToDown60LongBaseSeq2 = { + .clearance = { -32, 0, 80, 8, { 0b0001, 0 }, 0 }, + .allowedWallEdges = 0b1001, + }; + static constexpr SequenceDescriptor kDiagFlatToDown60LongBaseSeq3 = { + .clearance = { -32, 32, 56, 8, { 0b1111, 0 }, 0 }, + .allowedWallEdges = 0b0000, + }; + static constexpr SequenceDescriptor kDiagFlatToDown60LongBaseSeq4 = { + .clearance = { -32, 64, 56, 32, { 0b0100, 0 }, 0 }, + .allowedWallEdges = 0b0110, + }; + static constexpr SequenceDescriptor kDiagFlatToDown60LongBaseSeq5 = { + .clearance = { -64, 32, 56, 32, { 0b0001, 0 }, 0 }, + .allowedWallEdges = 0b1001, + }; + static constexpr SequenceDescriptor kDiagFlatToDown60LongBaseSeq6 = { + .clearance = { -64, 64, 0, 80, { 0b1111, 0 }, 0 }, + .allowedWallEdges = 0b0000, + }; + static constexpr SequenceDescriptor kDiagFlatToDown60LongBaseSeq7 = { + .clearance = { -64, 96, 0, 72, { 0b0100, 0 }, 0 }, + .allowedWallEdges = 0b0110, + }; + static constexpr SequenceDescriptor kDiagFlatToDown60LongBaseSeq8 = { + .clearance = { -96, 64, 0, 72, { 0b0001, 0 }, 0 }, + .allowedWallEdges = 0b1001, + }; + static constexpr SequenceDescriptor kDiagFlatToDown60LongBaseSeq9 = { + .clearance = { -96, 96, 0, 64, { 0b0010, 0 }, 0 }, + .allowedWallEdges = 0b0000, + }; + static constexpr SequenceDescriptor kDiagDown60ToFlatLongBaseSeq0 = { + .clearance = { 0, 0, 40, 104, { 0b1101, 0 }, 0 }, + .allowedWallEdges = 0b0000, + }; + static constexpr SequenceDescriptor kDiagDown60ToFlatLongBaseSeq1 = { + .clearance = { 0, 32, 40, 88, { 0b0100, 0 }, 0 }, + .allowedWallEdges = 0b0110, + }; + static constexpr SequenceDescriptor kDiagDown60ToFlatLongBaseSeq2 = { + .clearance = { -32, 0, 40, 88, { 0b0001, 0 }, 0 }, + .allowedWallEdges = 0b1001, + }; + static constexpr SequenceDescriptor kDiagDown60ToFlatLongBaseSeq3 = { + .clearance = { -32, 32, 8, 64, { 0b1111, 0 }, 0 }, + .allowedWallEdges = 0b0000, + }; + static constexpr SequenceDescriptor kDiagDown60ToFlatLongBaseSeq4 = { + .clearance = { -32, 64, 8, 40, { 0b0100, 0 }, 0 }, + .allowedWallEdges = 0b0110, + }; + static constexpr SequenceDescriptor kDiagDown60ToFlatLongBaseSeq5 = { + .clearance = { -64, 32, 8, 40, { 0b0001, 0 }, 0 }, + .allowedWallEdges = 0b1001, + }; + static constexpr SequenceDescriptor kDiagDown60ToFlatLongBaseSeq6 = { + .clearance = { -64, 64, 0, 32, { 0b1111, 0 }, 0 }, + .allowedWallEdges = 0b0000, + }; + static constexpr SequenceDescriptor kDiagDown60ToFlatLongBaseSeq7 = { + .clearance = { -64, 96, 0, 16, { 0b0100, 0 }, 0 }, + .allowedWallEdges = 0b0110, + }; + static constexpr SequenceDescriptor kDiagDown60ToFlatLongBaseSeq8 = { + .clearance = { -96, 64, 0, 16, { 0b0001, 0 }, 0 }, + .allowedWallEdges = 0b1001, + }; + static constexpr SequenceDescriptor kDiagDown60ToFlatLongBaseSeq9 = { + .clearance = { -96, 96, 0, 0, { 0b0010, 0 }, 0 }, + .allowedWallEdges = 0b0000, + }; + static constexpr SequenceDescriptor kLeftEighthDiveLoopUpToOrthogonalSeq0 = { + .clearance = { 0, 0, 0, 64, { 0b1101, 0 }, 0 }, + .allowedWallEdges = 0b0000, + }; + static constexpr SequenceDescriptor kLeftEighthDiveLoopUpToOrthogonalSeq1 = { + .clearance = { 0, 32, 0, 88, { 0b0100, 0 }, 0 }, + .allowedWallEdges = 0b0110, + }; + static constexpr SequenceDescriptor kLeftEighthDiveLoopUpToOrthogonalSeq2 = { + .clearance = { -32, 0, 0, 88, { 0b0001, 0 }, 0 }, + .allowedWallEdges = 0b1001, + }; + static constexpr SequenceDescriptor kLeftEighthDiveLoopUpToOrthogonalSeq3 = { + .clearance = { -32, 32, 32, 80, { 0b1111, 0 }, 0 }, + .allowedWallEdges = 0b0010, + }; + static constexpr SequenceDescriptor kLeftEighthDiveLoopUpToOrthogonalSeq4 = { + .clearance = { -64, 32, 80, 48, { 0b1111, 0 }, 0 }, + .allowedWallEdges = 0b1010, + }; + static constexpr SequenceDescriptor kLeftEighthDiveLoopUpToOrthogonalSeq5 = { + .clearance = { -96, 32, 112, 24, { 0b1111, 0 }, 0 }, + .allowedWallEdges = 0b1010, + }; + static constexpr SequenceDescriptor kRightEighthDiveLoopUpToOrthogonalSeq0 = { + .clearance = { 0, 0, 0, 64, { 0b1101, 0 }, 0 }, + .allowedWallEdges = 0b0000, + }; + static constexpr SequenceDescriptor kRightEighthDiveLoopUpToOrthogonalSeq1 = { + .clearance = { -32, 0, 0, 88, { 0b0001, 0 }, 0 }, + .allowedWallEdges = 0b1001, + }; + static constexpr SequenceDescriptor kRightEighthDiveLoopUpToOrthogonalSeq2 = { + .clearance = { 0, 32, 0, 88, { 0b0100, 0 }, 0 }, + .allowedWallEdges = 0b0110, + }; + static constexpr SequenceDescriptor kRightEighthDiveLoopUpToOrthogonalSeq3 = { + .clearance = { -32, 32, 32, 80, { 0b1111, 0 }, 0 }, + .allowedWallEdges = 0b0001, + }; + static constexpr SequenceDescriptor kRightEighthDiveLoopUpToOrthogonalSeq4 = { + .clearance = { -32, 64, 80, 48, { 0b1111, 0 }, 0 }, + .allowedWallEdges = 0b0101, + }; + static constexpr SequenceDescriptor kRightEighthDiveLoopUpToOrthogonalSeq5 = { + .clearance = { -32, 96, 112, 24, { 0b1111, 0 }, 0 }, + .allowedWallEdges = 0b0101, + }; + static constexpr SequenceDescriptor kLeftEighthDiveLoopDownToDiagSeq0 = { + .clearance = { 0, 0, 112, 24, { 0b1111, 0 }, 0 }, + .allowedWallEdges = 0b1010, + }; + static constexpr SequenceDescriptor kLeftEighthDiveLoopDownToDiagSeq1 = { + .clearance = { -32, 0, 80, 48, { 0b1111, 0 }, 0 }, + .allowedWallEdges = 0b1010, + }; + static constexpr SequenceDescriptor kLeftEighthDiveLoopDownToDiagSeq2 = { + .clearance = { -64, 0, 32, 80, { 0b1111, 0 }, 0 }, + .allowedWallEdges = 0b0010, + }; + static constexpr SequenceDescriptor kLeftEighthDiveLoopDownToDiagSeq3 = { + .clearance = { -64, -32, 0, 88, { 0b1000, 0 }, 0 }, + .allowedWallEdges = 0b1100, + }; + static constexpr SequenceDescriptor kLeftEighthDiveLoopDownToDiagSeq4 = { + .clearance = { -96, 0, 0, 88, { 0b0010, 0 }, 0 }, + .allowedWallEdges = 0b0011, + }; + static constexpr SequenceDescriptor kLeftEighthDiveLoopDownToDiagSeq5 = { + .clearance = { -96, -32, 0, 64, { 0b0001, 0 }, 0 }, + .allowedWallEdges = 0b0000, + }; + static constexpr SequenceDescriptor kRightEighthDiveLoopDownToDiagSeq0 = { + .clearance = { 0, 0, 112, 24, { 0b1111, 0 }, 0 }, + .allowedWallEdges = 0b1010, + }; + static constexpr SequenceDescriptor kRightEighthDiveLoopDownToDiagSeq1 = { + .clearance = { -32, 0, 80, 48, { 0b1111, 0 }, 0 }, + .allowedWallEdges = 0b1010, + }; + static constexpr SequenceDescriptor kRightEighthDiveLoopDownToDiagSeq2 = { + .clearance = { -64, 0, 32, 80, { 0b1111, 0 }, 0 }, + .allowedWallEdges = 0b1000, + }; + static constexpr SequenceDescriptor kRightEighthDiveLoopDownToDiagSeq3 = { + .clearance = { -64, 32, 0, 88, { 0b0100, 0 }, 0 }, + .allowedWallEdges = 0b0110, + }; + static constexpr SequenceDescriptor kRightEighthDiveLoopDownToDiagSeq4 = { + .clearance = { -96, 0, 0, 88, { 0b0001, 0 }, 0 }, + .allowedWallEdges = 0b1001, + }; + static constexpr SequenceDescriptor kRightEighthDiveLoopDownToDiagSeq5 = { + .clearance = { -96, 32, 0, 64, { 0b0010, 0 }, 0 }, + .allowedWallEdges = 0b0000, + }; + static constexpr SequenceData kSequenceDescriptorsByElement[] = { /* TrackElemType::Flat */ { 1, { kFlatSeq0 } }, /* TrackElemType::EndStation */ { 1, { kEndStationSeq0 } }, @@ -12609,6 +13003,46 @@ namespace OpenRCT2::TrackMetaData /* TrackElemType::InclinedBrakes */ { 1, { kDown25Seq0 } }, /* TrackElemType::DiagBooster */ { 4, { kDiagFlatSeq0, kDiagFlatSeq1, kDiagFlatSeq2, kDiagFlatSeq3 } }, + /* TrackElemType::DiagFlatToUp60LongBase */ + { 10, + { kDiagFlatToUp60LongBaseSeq0, kDiagFlatToUp60LongBaseSeq1, kDiagFlatToUp60LongBaseSeq2, kDiagFlatToUp60LongBaseSeq3, + kDiagFlatToUp60LongBaseSeq4, kDiagFlatToUp60LongBaseSeq5, kDiagFlatToUp60LongBaseSeq6, kDiagFlatToUp60LongBaseSeq7, + kDiagFlatToUp60LongBaseSeq8, kDiagFlatToUp60LongBaseSeq9 } }, + /* TrackElemType::DiagUp60ToFlatLongBase */ + { 10, + { kDiagUp60ToFlatLongBaseSeq0, kDiagUp60ToFlatLongBaseSeq1, kDiagUp60ToFlatLongBaseSeq2, kDiagUp60ToFlatLongBaseSeq3, + kDiagUp60ToFlatLongBaseSeq4, kDiagUp60ToFlatLongBaseSeq5, kDiagUp60ToFlatLongBaseSeq6, kDiagUp60ToFlatLongBaseSeq7, + kDiagUp60ToFlatLongBaseSeq8, kDiagUp60ToFlatLongBaseSeq9 } }, + /* TrackElemType::DiagFlatToDown60LongBase */ + { 10, + { kDiagFlatToDown60LongBaseSeq0, kDiagFlatToDown60LongBaseSeq1, kDiagFlatToDown60LongBaseSeq2, + kDiagFlatToDown60LongBaseSeq3, kDiagFlatToDown60LongBaseSeq4, kDiagFlatToDown60LongBaseSeq5, + kDiagFlatToDown60LongBaseSeq6, kDiagFlatToDown60LongBaseSeq7, kDiagFlatToDown60LongBaseSeq8, + kDiagFlatToDown60LongBaseSeq9 } }, + /* TrackElemType::DiagDown60ToFlatLongBase */ + { 10, + { kDiagDown60ToFlatLongBaseSeq0, kDiagDown60ToFlatLongBaseSeq1, kDiagDown60ToFlatLongBaseSeq2, + kDiagDown60ToFlatLongBaseSeq3, kDiagDown60ToFlatLongBaseSeq4, kDiagDown60ToFlatLongBaseSeq5, + kDiagDown60ToFlatLongBaseSeq6, kDiagDown60ToFlatLongBaseSeq7, kDiagDown60ToFlatLongBaseSeq8, + kDiagDown60ToFlatLongBaseSeq9 } }, + /* TrackElemType::LeftEighthDiveLoopUpToOrthogonal */ + { 6, + { kLeftEighthDiveLoopUpToOrthogonalSeq0, kLeftEighthDiveLoopUpToOrthogonalSeq1, kLeftEighthDiveLoopUpToOrthogonalSeq2, + kLeftEighthDiveLoopUpToOrthogonalSeq3, kLeftEighthDiveLoopUpToOrthogonalSeq4, + kLeftEighthDiveLoopUpToOrthogonalSeq5 } }, + /* TrackElemType::RightEighthDiveLoopUpToOrthogonal */ + { 6, + { kRightEighthDiveLoopUpToOrthogonalSeq0, kRightEighthDiveLoopUpToOrthogonalSeq1, + kRightEighthDiveLoopUpToOrthogonalSeq2, kRightEighthDiveLoopUpToOrthogonalSeq3, + kRightEighthDiveLoopUpToOrthogonalSeq4, kRightEighthDiveLoopUpToOrthogonalSeq5 } }, + /* TrackElemType::LeftEighthDiveLoopDownToDiag */ + { 6, + { kLeftEighthDiveLoopDownToDiagSeq0, kLeftEighthDiveLoopDownToDiagSeq1, kLeftEighthDiveLoopDownToDiagSeq2, + kLeftEighthDiveLoopDownToDiagSeq3, kLeftEighthDiveLoopDownToDiagSeq4, kLeftEighthDiveLoopDownToDiagSeq5 } }, + /* TrackElemType::RightEighthDiveLoopDownToDiag */ + { 6, + { kRightEighthDiveLoopDownToDiagSeq0, kRightEighthDiveLoopDownToDiagSeq1, kRightEighthDiveLoopDownToDiagSeq2, + kRightEighthDiveLoopDownToDiagSeq3, kRightEighthDiveLoopDownToDiagSeq4, kRightEighthDiveLoopDownToDiagSeq5 } }, }; static constexpr auto BuildDescriptorTable() diff --git a/src/openrct2/ride/Vehicle.cpp b/src/openrct2/ride/Vehicle.cpp index 8dfa7c7be1..d8c4b290f2 100644 --- a/src/openrct2/ride/Vehicle.cpp +++ b/src/openrct2/ride/Vehicle.cpp @@ -2308,7 +2308,7 @@ static void test_finish(Ride& ride) ride.lifecycle_flags &= ~RIDE_LIFECYCLE_TEST_IN_PROGRESS; ride.lifecycle_flags |= RIDE_LIFECYCLE_TESTED; - auto& rideStations = ride.GetStations(); + auto rideStations = ride.GetStations(); for (int32_t i = ride.num_stations - 1; i >= 1; i--) { if (rideStations[i - 1].SegmentTime != 0) @@ -5485,6 +5485,36 @@ void Vehicle::ApplyStopBlockBrake() } } +void Vehicle::ApplyCableLiftBlockBrake(bool brakeClosed) +{ + // If we are already on the cable lift, ignore the brake + if (status == Vehicle::Status::TravellingCableLift) + return; + + // Slow down if travelling faster than 4mph + if (velocity > kBlockBrakeBaseSpeed) + { + velocity -= velocity >> 3; + acceleration = 0; + } + // Once moving slow enough, keep moving forward until lined up with the catch car + else if (track_progress <= 18) + { + velocity = kBlockBrakeBaseSpeed; + acceleration = 0; + } + // Once in position, stop, and wait for the catch car + if (velocity > 0 && track_progress >= 18) + { + velocity = 0; + acceleration = 0; + if (!brakeClosed) + SetState(Vehicle::Status::WaitingForCableLift, sub_state); + else + _vehicleMotionTrackFlags |= VEHICLE_UPDATE_MOTION_TRACK_FLAG_VEHICLE_AT_BLOCK_BRAKE; + } +} + /** * * rct2: 0x006DAC43 @@ -5518,6 +5548,20 @@ void Vehicle::CheckAndApplyBlockSectionStopSite() switch (trackType) { case TrackElemType::BlockBrakes: + // Check if this brake is the start of a cable lift + if (curRide->lifecycle_flags & RIDE_LIFECYCLE_CABLE_LIFT) + { + CoordsXYE track; + int32_t zUnused; + int32_t direction; + if (TrackBlockGetNextFromZero(TrackLocation, *curRide, GetTrackDirection(), &track, &zUnused, &direction, false) + && track.element != nullptr && track.element->AsTrack()->HasCableLift()) + { + ApplyCableLiftBlockBrake(curRide->IsBlockSectioned() && trackElement->AsTrack()->IsBrakeClosed()); + break; + } + } + [[fallthrough]]; case TrackElemType::DiagBlockBrakes: if (curRide->IsBlockSectioned() && trackElement->AsTrack()->IsBrakeClosed()) ApplyStopBlockBrake(); @@ -5564,15 +5608,11 @@ void Vehicle::UpdateVelocity() } if (HasFlag(VehicleFlags::StoppedOnHoldingBrake)) { - vertical_drop_countdown--; - if (vertical_drop_countdown == -70) - { - ClearFlag(VehicleFlags::StoppedOnHoldingBrake); - } - if (vertical_drop_countdown >= 0) + if (vertical_drop_countdown > 0) { nextVelocity = 0; acceleration = 0; + vertical_drop_countdown--; } } velocity = nextVelocity; @@ -5581,56 +5621,13 @@ void Vehicle::UpdateVelocity() _vehicleVelocityF64E0C = (nextVelocity >> 10) * 42; } -static void block_brakes_open_previous_section( - const Ride& ride, const CoordsXYZ& vehicleTrackLocation, TileElement* tileElement) +static void BlockBrakesOpenPreviousSection(const Ride& ride, const CoordsXYZ& vehicleTrackLocation, TileElement* tileElement) { - auto location = vehicleTrackLocation; - TrackBeginEnd trackBeginEnd, slowTrackBeginEnd; - TileElement slowTileElement = *tileElement; - bool counter = true; - CoordsXY slowLocation = location; - do - { - if (!TrackBlockGetPrevious({ location, tileElement }, &trackBeginEnd)) - { - return; - } - if (trackBeginEnd.begin_x == vehicleTrackLocation.x && trackBeginEnd.begin_y == vehicleTrackLocation.y - && tileElement == trackBeginEnd.begin_element) - { - return; - } - - location.x = trackBeginEnd.end_x; - location.y = trackBeginEnd.end_y; - location.z = trackBeginEnd.begin_z; - tileElement = trackBeginEnd.begin_element; - - // #2081: prevent infinite loop - counter = !counter; - if (counter) - { - TrackBlockGetPrevious({ slowLocation, &slowTileElement }, &slowTrackBeginEnd); - slowLocation.x = slowTrackBeginEnd.end_x; - slowLocation.y = slowTrackBeginEnd.end_y; - slowTileElement = *(slowTrackBeginEnd.begin_element); - if (slowLocation == location && slowTileElement.GetBaseZ() == tileElement->GetBaseZ() - && slowTileElement.GetType() == tileElement->GetType() - && slowTileElement.GetDirection() == tileElement->GetDirection()) - { - return; - } - } - } while (!(trackBeginEnd.begin_element->AsTrack()->IsBlockStart())); - - // Get the start of the track block instead of the end - location = { trackBeginEnd.begin_x, trackBeginEnd.begin_y, trackBeginEnd.begin_z }; - auto trackOrigin = MapGetTrackElementAtOfTypeSeq(location, trackBeginEnd.begin_element->AsTrack()->GetTrackType(), 0); - if (trackOrigin == nullptr) - { + CoordsXYZ location = vehicleTrackLocation; + TrackElement* trackElement = TrackGetPreviousBlock(location, tileElement); + if (trackElement == nullptr) return; - } - auto trackElement = trackOrigin->AsTrack(); + SetBrakeClosedMultiTile(*trackElement, location, false); MapInvalidateElement(location, reinterpret_cast(trackElement)); @@ -6925,7 +6922,7 @@ bool Vehicle::UpdateTrackMotionForwardsGetNewTrack( } } MapInvalidateElement(TrackLocation, tileElement); - block_brakes_open_previous_section(curRide, TrackLocation, tileElement); + BlockBrakesOpenPreviousSection(curRide, TrackLocation, tileElement); if (TrackTypeIsBlockBrakes(trackType)) { BlockBrakeSetLinkedBrakesClosed(TrackLocation, *tileElement->AsTrack(), true); @@ -7060,6 +7057,10 @@ bool Vehicle::UpdateTrackMotionForwardsGetNewTrack( SetTrackDirection(location.direction); SetTrackType(trackType); PopulateBrakeSpeed(TrackLocation, *tileElement->AsTrack()); + if (HasFlag(VehicleFlags::StoppedOnHoldingBrake) && vertical_drop_countdown <= 0) + { + ClearFlag(VehicleFlags::StoppedOnHoldingBrake); + } if (trackType == TrackElemType::OnRidePhoto) { trigger_on_ride_photo(TrackLocation, tileElement); @@ -7470,7 +7471,10 @@ bool Vehicle::UpdateTrackMotionBackwardsGetNewTrack(TrackElemType trackType, con SetTrackType(trackType); SetTrackDirection(direction); PopulateBrakeSpeed(TrackLocation, *tileElement->AsTrack()); - + if (HasFlag(VehicleFlags::StoppedOnHoldingBrake) && vertical_drop_countdown <= 0) + { + ClearFlag(VehicleFlags::StoppedOnHoldingBrake); + } // There are two bytes before the move info list uint16_t trackTotalProgress = GetTrackProgress(); *progress = trackTotalProgress - 1; diff --git a/src/openrct2/ride/Vehicle.h b/src/openrct2/ride/Vehicle.h index e455fe763b..c5c03a82ef 100644 --- a/src/openrct2/ride/Vehicle.h +++ b/src/openrct2/ride/Vehicle.h @@ -347,6 +347,7 @@ private: void UpdateTrackMotionUpStopCheck() const; void ApplyNonStopBlockBrake(); void ApplyStopBlockBrake(); + void ApplyCableLiftBlockBrake(bool brakeClosed); void CheckAndApplyBlockSectionStopSite(); void UpdateVelocity(); void UpdateSpinningCar(); diff --git a/src/openrct2/ride/VehicleSubpositionData.cpp b/src/openrct2/ride/VehicleSubpositionData.cpp index 6056080f71..79313ae97e 100644 --- a/src/openrct2/ride/VehicleSubpositionData.cpp +++ b/src/openrct2/ride/VehicleSubpositionData.cpp @@ -27265,11 +27265,981 @@ CREATE_VEHICLE_INFO(TrackVehicleInfoRightEighthBankToOrthogonalDown253, { }) +CREATE_VEHICLE_INFO(TrackVehicleInfoDiagFlatToUp60LongBase0,{ + { 15, 16, 0, 4, 0, 0 },{ 14, 17, 0, 4, 0, 0 },{ 13, 18, 0, 4, 0, 0 },{ 12, 19, 0, 4, 0, 0 },{ 11, 20, 0, 4, 0, 0 }, + { 10, 21, 0, 4, 0, 0 },{ 9, 22, 0, 4, 50, 0 },{ 8, 23, 1, 4, 50, 0 },{ 7, 24, 1, 4, 50, 0 },{ 6, 25, 1, 4, 50, 0 }, + { 5, 26, 1, 4, 50, 0 },{ 4, 27, 1, 4, 50, 0 },{ 3, 28, 2, 4, 50, 0 },{ 2, 29, 2, 4, 50, 0 },{ 1, 30, 2, 4, 50, 0 }, + { 0, 31, 2, 4, 50, 0 },{ -1, 32, 3, 4, 50, 0 },{ -2, 33, 3, 4, 50, 0 },{ -3, 34, 3, 4, 50, 0 },{ -4, 35, 4, 4, 50, 0 }, + { -5, 36, 4, 4, 50, 0 },{ -6, 37, 4, 4, 51, 0 },{ -7, 38, 5, 4, 51, 0 },{ -8, 39, 5, 4, 51, 0 },{ -9, 40, 6, 4, 51, 0 }, + { -10, 41, 6, 4, 51, 0 },{ -11, 42, 6, 4, 51, 0 },{ -12, 43, 7, 4, 51, 0 },{ -13, 44, 7, 4, 51, 0 },{ -14, 45, 8, 4, 51, 0 }, + { -15, 46, 9, 4, 51, 0 },{ -16, 47, 9, 4, 51, 0 },{ -17, 48, 10, 4, 51, 0 },{ -18, 49, 10, 4, 2, 0 },{ -19, 50, 11, 4, 2, 0 }, + { -20, 51, 12, 4, 2, 0 },{ -21, 52, 12, 4, 2, 0 },{ -22, 53, 13, 4, 2, 0 },{ -23, 54, 14, 4, 2, 0 },{ -24, 55, 14, 4, 2, 0 }, + { -25, 56, 15, 4, 2, 0 },{ -26, 57, 16, 4, 2, 0 },{ -27, 58, 17, 4, 2, 0 },{ -28, 59, 17, 4, 2, 0 },{ -29, 60, 18, 4, 2, 0 }, + { -30, 61, 19, 4, 2, 0 },{ -31, 62, 20, 4, 2, 0 },{ -32, 63, 21, 4, 2, 0 },{ -33, 64, 22, 4, 2, 0 },{ -34, 65, 23, 4, 2, 0 }, + { -35, 66, 24, 4, 2, 0 },{ -36, 67, 24, 4, 2, 0 },{ -37, 68, 25, 4, 2, 0 },{ -38, 69, 26, 4, 2, 0 },{ -39, 70, 27, 4, 2, 0 }, + { -40, 71, 28, 4, 2, 0 },{ -41, 72, 29, 4, 3, 0 },{ -42, 73, 30, 4, 3, 0 },{ -43, 74, 31, 4, 3, 0 },{ -44, 75, 32, 4, 3, 0 }, + { -45, 76, 33, 4, 3, 0 },{ -46, 77, 34, 4, 3, 0 },{ -47, 78, 35, 4, 3, 0 },{ -48, 79, 36, 4, 3, 0 },{ -48, 79, 37, 4, 3, 0 }, + { -49, 80, 38, 4, 3, 0 },{ -50, 81, 39, 4, 3, 0 },{ -51, 82, 40, 4, 3, 0 },{ -52, 83, 41, 4, 3, 0 },{ -52, 83, 42, 4, 3, 0 }, + { -53, 84, 43, 4, 3, 0 },{ -54, 85, 44, 4, 3, 0 },{ -55, 86, 45, 4, 3, 0 },{ -55, 86, 46, 4, 3, 0 },{ -56, 87, 47, 4, 3, 0 }, + { -57, 88, 48, 4, 3, 0 },{ -57, 88, 49, 4, 3, 0 },{ -58, 89, 50, 4, 3, 0 },{ -59, 90, 51, 4, 3, 0 },{ -59, 90, 52, 4, 3, 0 }, + { -60, 91, 53, 4, 3, 0 },{ -61, 92, 54, 4, 3, 0 },{ -61, 92, 55, 4, 3, 0 },{ -62, 93, 56, 4, 3, 0 },{ -63, 94, 57, 4, 3, 0 }, + { -63, 94, 58, 4, 3, 0 },{ -64, 95, 59, 4, 3, 0 },{ -65, 96, 60, 4, 3, 0 },{ -65, 96, 61, 4, 3, 0 },{ -66, 97, 62, 4, 3, 0 }, + { -67, 98, 63, 4, 3, 0 },{ -67, 98, 64, 4, 3, 0 },{ -68, 99, 65, 4, 3, 0 },{ -68, 99, 66, 4, 3, 0 },{ -69, 100, 67, 4, 3, 0 }, + { -70, 101, 68, 4, 52, 0 },{ -70, 101, 69, 4, 52, 0 },{ -71, 102, 70, 4, 52, 0 },{ -71, 102, 71, 4, 52, 0 },{ -72, 103, 72, 4, 52, 0 }, + { -72, 103, 73, 4, 52, 0 },{ -73, 104, 74, 4, 52, 0 },{ -73, 104, 75, 4, 52, 0 },{ -74, 105, 76, 4, 52, 0 },{ -75, 106, 77, 4, 52, 0 }, + { -75, 106, 78, 4, 52, 0 },{ -76, 107, 79, 4, 52, 0 },{ -76, 107, 80, 4, 52, 0 },{ -77, 108, 81, 4, 52, 0 },{ -77, 108, 82, 4, 52, 0 }, + { -78, 109, 83, 4, 52, 0 },{ -78, 109, 84, 4, 52, 0 },{ -79, 110, 85, 4, 52, 0 },{ -79, 110, 86, 4, 52, 0 },{ -80, 111, 87, 4, 52, 0 }, + { -80, 111, 88, 4, 52, 0 },}) +CREATE_VEHICLE_INFO(TrackVehicleInfoDiagFlatToUp60LongBase1,{ + { 16, 16, 0, 12, 0, 0 },{ 17, 17, 0, 12, 0, 0 },{ 18, 18, 0, 12, 0, 0 },{ 19, 19, 0, 12, 0, 0 },{ 20, 20, 0, 12, 0, 0 }, + { 21, 21, 0, 12, 0, 0 },{ 22, 22, 0, 12, 0, 0 },{ 23, 23, 0, 12, 50, 0 },{ 24, 24, 1, 12, 50, 0 },{ 25, 25, 1, 12, 50, 0 }, + { 26, 26, 1, 12, 50, 0 },{ 27, 27, 1, 12, 50, 0 },{ 28, 28, 1, 12, 50, 0 },{ 29, 29, 2, 12, 50, 0 },{ 30, 30, 2, 12, 50, 0 }, + { 31, 31, 2, 12, 50, 0 },{ 32, 32, 2, 12, 50, 0 },{ 33, 33, 3, 12, 50, 0 },{ 34, 34, 3, 12, 50, 0 },{ 35, 35, 3, 12, 50, 0 }, + { 36, 36, 4, 12, 50, 0 },{ 37, 37, 4, 12, 50, 0 },{ 38, 38, 4, 12, 51, 0 },{ 39, 39, 5, 12, 51, 0 },{ 40, 40, 5, 12, 51, 0 }, + { 41, 41, 6, 12, 51, 0 },{ 42, 42, 6, 12, 51, 0 },{ 43, 43, 6, 12, 51, 0 },{ 44, 44, 7, 12, 51, 0 },{ 45, 45, 7, 12, 51, 0 }, + { 46, 46, 8, 12, 51, 0 },{ 47, 47, 9, 12, 51, 0 },{ 48, 48, 9, 12, 51, 0 },{ 49, 49, 10, 12, 51, 0 },{ 50, 50, 10, 12, 2, 0 }, + { 51, 51, 11, 12, 2, 0 },{ 52, 52, 12, 12, 2, 0 },{ 53, 53, 12, 12, 2, 0 },{ 54, 54, 13, 12, 2, 0 },{ 55, 55, 14, 12, 2, 0 }, + { 56, 56, 14, 12, 2, 0 },{ 57, 57, 15, 12, 2, 0 },{ 58, 58, 16, 12, 2, 0 },{ 59, 59, 17, 12, 2, 0 },{ 60, 60, 17, 12, 2, 0 }, + { 61, 61, 18, 12, 2, 0 },{ 62, 62, 19, 12, 2, 0 },{ 63, 63, 20, 12, 2, 0 },{ 64, 64, 21, 12, 2, 0 },{ 65, 65, 22, 12, 2, 0 }, + { 66, 66, 23, 12, 2, 0 },{ 67, 67, 24, 12, 2, 0 },{ 68, 68, 24, 12, 2, 0 },{ 69, 69, 25, 12, 2, 0 },{ 70, 70, 26, 12, 2, 0 }, + { 71, 71, 27, 12, 2, 0 },{ 72, 72, 28, 12, 2, 0 },{ 73, 73, 29, 12, 3, 0 },{ 74, 74, 30, 12, 3, 0 },{ 75, 75, 31, 12, 3, 0 }, + { 76, 76, 32, 12, 3, 0 },{ 77, 77, 33, 12, 3, 0 },{ 78, 78, 34, 12, 3, 0 },{ 79, 79, 35, 12, 3, 0 },{ 80, 80, 36, 12, 3, 0 }, + { 80, 80, 37, 12, 3, 0 },{ 81, 81, 38, 12, 3, 0 },{ 82, 82, 39, 12, 3, 0 },{ 83, 83, 40, 12, 3, 0 },{ 84, 84, 41, 12, 3, 0 }, + { 84, 84, 42, 12, 3, 0 },{ 85, 85, 43, 12, 3, 0 },{ 86, 86, 44, 12, 3, 0 },{ 87, 87, 45, 12, 3, 0 },{ 87, 87, 46, 12, 3, 0 }, + { 88, 88, 47, 12, 3, 0 },{ 89, 89, 48, 12, 3, 0 },{ 89, 89, 49, 12, 3, 0 },{ 90, 90, 50, 12, 3, 0 },{ 91, 91, 51, 12, 3, 0 }, + { 91, 91, 52, 12, 3, 0 },{ 92, 92, 53, 12, 3, 0 },{ 93, 93, 54, 12, 3, 0 },{ 93, 93, 55, 12, 3, 0 },{ 94, 94, 56, 12, 3, 0 }, + { 95, 95, 57, 12, 3, 0 },{ 95, 95, 58, 12, 3, 0 },{ 96, 96, 59, 12, 3, 0 },{ 97, 97, 60, 12, 3, 0 },{ 97, 97, 61, 12, 3, 0 }, + { 98, 98, 62, 12, 3, 0 },{ 99, 99, 63, 12, 3, 0 },{ 99, 99, 64, 12, 3, 0 },{ 100, 100, 65, 12, 3, 0 },{ 100, 100, 66, 12, 3, 0 }, + { 101, 101, 67, 12, 3, 0 },{ 102, 102, 68, 12, 52, 0 },{ 102, 102, 69, 12, 52, 0 },{ 103, 103, 70, 12, 52, 0 },{ 103, 103, 71, 12, 52, 0 }, + { 104, 104, 72, 12, 52, 0 },{ 104, 104, 73, 12, 52, 0 },{ 105, 105, 74, 12, 52, 0 },{ 105, 105, 75, 12, 52, 0 },{ 106, 106, 76, 12, 52, 0 }, + { 107, 107, 77, 12, 52, 0 },{ 107, 107, 78, 12, 52, 0 },{ 108, 108, 79, 12, 52, 0 },{ 108, 108, 80, 12, 52, 0 },{ 109, 109, 81, 12, 52, 0 }, + { 109, 109, 82, 12, 52, 0 },{ 110, 110, 83, 12, 52, 0 },{ 110, 110, 84, 12, 52, 0 },{ 111, 111, 85, 12, 52, 0 },{ 111, 111, 86, 12, 52, 0 }, + { 112, 112, 87, 12, 52, 0 },}) +CREATE_VEHICLE_INFO(TrackVehicleInfoDiagFlatToUp60LongBase2,{ + { 16, 15, 0, 20, 0, 0 },{ 17, 14, 0, 20, 0, 0 },{ 18, 13, 0, 20, 0, 0 },{ 19, 12, 0, 20, 0, 0 },{ 20, 11, 0, 20, 0, 0 }, + { 21, 10, 0, 20, 0, 0 },{ 22, 9, 0, 20, 0, 0 },{ 23, 8, 0, 20, 50, 0 },{ 24, 7, 1, 20, 50, 0 },{ 25, 6, 1, 20, 50, 0 }, + { 26, 5, 1, 20, 50, 0 },{ 27, 4, 1, 20, 50, 0 },{ 28, 3, 1, 20, 50, 0 },{ 29, 2, 2, 20, 50, 0 },{ 30, 1, 2, 20, 50, 0 }, + { 31, 0, 2, 20, 50, 0 },{ 32, -1, 2, 20, 50, 0 },{ 33, -2, 3, 20, 50, 0 },{ 34, -3, 3, 20, 50, 0 },{ 35, -4, 3, 20, 50, 0 }, + { 36, -5, 4, 20, 50, 0 },{ 37, -6, 4, 20, 50, 0 },{ 38, -7, 4, 20, 51, 0 },{ 39, -8, 5, 20, 51, 0 },{ 40, -9, 5, 20, 51, 0 }, + { 41, -10, 6, 20, 51, 0 },{ 42, -11, 6, 20, 51, 0 },{ 43, -12, 6, 20, 51, 0 },{ 44, -13, 7, 20, 51, 0 },{ 45, -14, 7, 20, 51, 0 }, + { 46, -15, 8, 20, 51, 0 },{ 47, -16, 9, 20, 51, 0 },{ 48, -17, 9, 20, 51, 0 },{ 49, -18, 10, 20, 51, 0 },{ 50, -19, 10, 20, 2, 0 }, + { 51, -20, 11, 20, 2, 0 },{ 52, -21, 12, 20, 2, 0 },{ 53, -22, 12, 20, 2, 0 },{ 54, -23, 13, 20, 2, 0 },{ 55, -24, 14, 20, 2, 0 }, + { 56, -25, 14, 20, 2, 0 },{ 57, -26, 15, 20, 2, 0 },{ 58, -27, 16, 20, 2, 0 },{ 59, -28, 17, 20, 2, 0 },{ 60, -29, 17, 20, 2, 0 }, + { 61, -30, 18, 20, 2, 0 },{ 62, -31, 19, 20, 2, 0 },{ 63, -32, 20, 20, 2, 0 },{ 64, -33, 21, 20, 2, 0 },{ 65, -34, 22, 20, 2, 0 }, + { 66, -35, 23, 20, 2, 0 },{ 67, -36, 24, 20, 2, 0 },{ 68, -37, 24, 20, 2, 0 },{ 69, -38, 25, 20, 2, 0 },{ 70, -39, 26, 20, 2, 0 }, + { 71, -40, 27, 20, 2, 0 },{ 72, -41, 28, 20, 2, 0 },{ 73, -42, 29, 20, 3, 0 },{ 74, -43, 30, 20, 3, 0 },{ 75, -44, 31, 20, 3, 0 }, + { 76, -45, 32, 20, 3, 0 },{ 77, -46, 33, 20, 3, 0 },{ 78, -47, 34, 20, 3, 0 },{ 79, -48, 35, 20, 3, 0 },{ 80, -49, 36, 20, 3, 0 }, + { 80, -49, 37, 20, 3, 0 },{ 81, -50, 38, 20, 3, 0 },{ 82, -51, 39, 20, 3, 0 },{ 83, -52, 40, 20, 3, 0 },{ 84, -53, 41, 20, 3, 0 }, + { 84, -53, 42, 20, 3, 0 },{ 85, -54, 43, 20, 3, 0 },{ 86, -55, 44, 20, 3, 0 },{ 87, -56, 45, 20, 3, 0 },{ 87, -56, 46, 20, 3, 0 }, + { 88, -57, 47, 20, 3, 0 },{ 89, -58, 48, 20, 3, 0 },{ 89, -58, 49, 20, 3, 0 },{ 90, -59, 50, 20, 3, 0 },{ 91, -60, 51, 20, 3, 0 }, + { 91, -60, 52, 20, 3, 0 },{ 92, -61, 53, 20, 3, 0 },{ 93, -62, 54, 20, 3, 0 },{ 93, -62, 55, 20, 3, 0 },{ 94, -63, 56, 20, 3, 0 }, + { 95, -64, 57, 20, 3, 0 },{ 95, -64, 58, 20, 3, 0 },{ 96, -65, 59, 20, 3, 0 },{ 97, -66, 60, 20, 3, 0 },{ 97, -66, 61, 20, 3, 0 }, + { 98, -67, 62, 20, 3, 0 },{ 99, -68, 63, 20, 3, 0 },{ 99, -68, 64, 20, 3, 0 },{ 100, -69, 65, 20, 3, 0 },{ 100, -69, 66, 20, 3, 0 }, + { 101, -70, 67, 20, 3, 0 },{ 102, -71, 68, 20, 52, 0 },{ 102, -71, 69, 20, 52, 0 },{ 103, -72, 70, 20, 52, 0 },{ 103, -72, 71, 20, 52, 0 }, + { 104, -73, 72, 20, 52, 0 },{ 104, -73, 73, 20, 52, 0 },{ 105, -74, 74, 20, 52, 0 },{ 105, -74, 75, 20, 52, 0 },{ 106, -75, 76, 20, 52, 0 }, + { 107, -76, 77, 20, 52, 0 },{ 107, -76, 78, 20, 52, 0 },{ 108, -77, 79, 20, 52, 0 },{ 108, -77, 80, 20, 52, 0 },{ 109, -78, 81, 20, 52, 0 }, + { 109, -78, 82, 20, 52, 0 },{ 110, -79, 83, 20, 52, 0 },{ 110, -79, 84, 20, 52, 0 },{ 111, -80, 85, 20, 52, 0 },{ 111, -80, 86, 20, 52, 0 }, + { 112, -81, 87, 20, 52, 0 },}) +CREATE_VEHICLE_INFO(TrackVehicleInfoDiagFlatToUp60LongBase3,{ + { 15, 15, 0, 28, 0, 0 },{ 14, 14, 0, 28, 0, 0 },{ 13, 13, 0, 28, 0, 0 },{ 12, 12, 0, 28, 0, 0 },{ 11, 11, 0, 28, 0, 0 }, + { 10, 10, 0, 28, 0, 0 },{ 9, 9, 0, 28, 50, 0 },{ 8, 8, 1, 28, 50, 0 },{ 7, 7, 1, 28, 50, 0 },{ 6, 6, 1, 28, 50, 0 }, + { 5, 5, 1, 28, 50, 0 },{ 4, 4, 1, 28, 50, 0 },{ 3, 3, 2, 28, 50, 0 },{ 2, 2, 2, 28, 50, 0 },{ 1, 1, 2, 28, 50, 0 }, + { 0, 0, 2, 28, 50, 0 },{ -1, -1, 3, 28, 50, 0 },{ -2, -2, 3, 28, 50, 0 },{ -3, -3, 3, 28, 50, 0 },{ -4, -4, 4, 28, 50, 0 }, + { -5, -5, 4, 28, 50, 0 },{ -6, -6, 4, 28, 51, 0 },{ -7, -7, 5, 28, 51, 0 },{ -8, -8, 5, 28, 51, 0 },{ -9, -9, 6, 28, 51, 0 }, + { -10, -10, 6, 28, 51, 0 },{ -11, -11, 6, 28, 51, 0 },{ -12, -12, 7, 28, 51, 0 },{ -13, -13, 7, 28, 51, 0 },{ -14, -14, 8, 28, 51, 0 }, + { -15, -15, 9, 28, 51, 0 },{ -16, -16, 9, 28, 51, 0 },{ -17, -17, 10, 28, 51, 0 },{ -18, -18, 10, 28, 2, 0 },{ -19, -19, 11, 28, 2, 0 }, + { -20, -20, 12, 28, 2, 0 },{ -21, -21, 12, 28, 2, 0 },{ -22, -22, 13, 28, 2, 0 },{ -23, -23, 14, 28, 2, 0 },{ -24, -24, 14, 28, 2, 0 }, + { -25, -25, 15, 28, 2, 0 },{ -26, -26, 16, 28, 2, 0 },{ -27, -27, 17, 28, 2, 0 },{ -28, -28, 17, 28, 2, 0 },{ -29, -29, 18, 28, 2, 0 }, + { -30, -30, 19, 28, 2, 0 },{ -31, -31, 20, 28, 2, 0 },{ -32, -32, 21, 28, 2, 0 },{ -33, -33, 22, 28, 2, 0 },{ -34, -34, 23, 28, 2, 0 }, + { -35, -35, 24, 28, 2, 0 },{ -36, -36, 24, 28, 2, 0 },{ -37, -37, 25, 28, 2, 0 },{ -38, -38, 26, 28, 2, 0 },{ -39, -39, 27, 28, 2, 0 }, + { -40, -40, 28, 28, 2, 0 },{ -41, -41, 29, 28, 3, 0 },{ -42, -42, 30, 28, 3, 0 },{ -43, -43, 31, 28, 3, 0 },{ -44, -44, 32, 28, 3, 0 }, + { -45, -45, 33, 28, 3, 0 },{ -46, -46, 34, 28, 3, 0 },{ -47, -47, 35, 28, 3, 0 },{ -48, -48, 36, 28, 3, 0 },{ -48, -48, 37, 28, 3, 0 }, + { -49, -49, 38, 28, 3, 0 },{ -50, -50, 39, 28, 3, 0 },{ -51, -51, 40, 28, 3, 0 },{ -52, -52, 41, 28, 3, 0 },{ -52, -52, 42, 28, 3, 0 }, + { -53, -53, 43, 28, 3, 0 },{ -54, -54, 44, 28, 3, 0 },{ -55, -55, 45, 28, 3, 0 },{ -55, -55, 46, 28, 3, 0 },{ -56, -56, 47, 28, 3, 0 }, + { -57, -57, 48, 28, 3, 0 },{ -57, -57, 49, 28, 3, 0 },{ -58, -58, 50, 28, 3, 0 },{ -59, -59, 51, 28, 3, 0 },{ -59, -59, 52, 28, 3, 0 }, + { -60, -60, 53, 28, 3, 0 },{ -61, -61, 54, 28, 3, 0 },{ -61, -61, 55, 28, 3, 0 },{ -62, -62, 56, 28, 3, 0 },{ -63, -63, 57, 28, 3, 0 }, + { -63, -63, 58, 28, 3, 0 },{ -64, -64, 59, 28, 3, 0 },{ -65, -65, 60, 28, 3, 0 },{ -65, -65, 61, 28, 3, 0 },{ -66, -66, 62, 28, 3, 0 }, + { -67, -67, 63, 28, 3, 0 },{ -67, -67, 64, 28, 3, 0 },{ -68, -68, 65, 28, 3, 0 },{ -68, -68, 66, 28, 3, 0 },{ -69, -69, 67, 28, 3, 0 }, + { -70, -70, 68, 28, 52, 0 },{ -70, -70, 69, 28, 52, 0 },{ -71, -71, 70, 28, 52, 0 },{ -71, -71, 71, 28, 52, 0 },{ -72, -72, 72, 28, 52, 0 }, + { -72, -72, 73, 28, 52, 0 },{ -73, -73, 74, 28, 52, 0 },{ -73, -73, 75, 28, 52, 0 },{ -74, -74, 76, 28, 52, 0 },{ -75, -75, 77, 28, 52, 0 }, + { -75, -75, 78, 28, 52, 0 },{ -76, -76, 79, 28, 52, 0 },{ -76, -76, 80, 28, 52, 0 },{ -77, -77, 81, 28, 52, 0 },{ -77, -77, 82, 28, 52, 0 }, + { -78, -78, 83, 28, 52, 0 },{ -78, -78, 84, 28, 52, 0 },{ -79, -79, 85, 28, 52, 0 },{ -79, -79, 86, 28, 52, 0 },{ -80, -80, 87, 28, 52, 0 }, + { -80, -80, 88, 28, 52, 0 },}) +CREATE_VEHICLE_INFO(TrackVehicleInfoDiagUp60ToFlatLongBase0,{ + { 15, 16, 1, 4, 52, 0 },{ 15, 16, 2, 4, 52, 0 },{ 14, 17, 3, 4, 52, 0 },{ 14, 17, 4, 4, 52, 0 },{ 13, 18, 5, 4, 52, 0 }, + { 13, 18, 6, 4, 52, 0 },{ 12, 19, 7, 4, 52, 0 },{ 12, 19, 8, 4, 52, 0 },{ 11, 20, 9, 4, 52, 0 },{ 11, 20, 10, 4, 52, 0 }, + { 10, 21, 11, 4, 52, 0 },{ 9, 22, 12, 4, 52, 0 },{ 9, 22, 13, 4, 52, 0 },{ 8, 23, 14, 4, 52, 0 },{ 8, 23, 15, 4, 52, 0 }, + { 7, 24, 16, 4, 52, 0 },{ 7, 24, 17, 4, 52, 0 },{ 6, 25, 18, 4, 52, 0 },{ 6, 25, 19, 4, 52, 0 },{ 5, 26, 20, 4, 3, 0 }, + { 4, 27, 21, 4, 3, 0 },{ 4, 27, 22, 4, 3, 0 },{ 3, 28, 23, 4, 3, 0 },{ 3, 28, 24, 4, 3, 0 },{ 2, 29, 25, 4, 3, 0 }, + { 1, 30, 26, 4, 3, 0 },{ 1, 30, 27, 4, 3, 0 },{ 0, 31, 28, 4, 3, 0 },{ -1, 32, 29, 4, 3, 0 },{ -1, 32, 30, 4, 3, 0 }, + { -2, 33, 31, 4, 3, 0 },{ -2, 33, 32, 4, 3, 0 },{ -3, 34, 33, 4, 3, 0 },{ -4, 35, 34, 4, 3, 0 },{ -4, 35, 35, 4, 3, 0 }, + { -5, 36, 36, 4, 3, 0 },{ -6, 37, 37, 4, 3, 0 },{ -7, 38, 38, 4, 3, 0 },{ -7, 38, 39, 4, 3, 0 },{ -8, 39, 40, 4, 3, 0 }, + { -9, 40, 41, 4, 3, 0 },{ -9, 40, 42, 4, 3, 0 },{ -10, 41, 43, 4, 3, 0 },{ -11, 42, 44, 4, 3, 0 },{ -12, 43, 45, 4, 3, 0 }, + { -12, 43, 46, 4, 3, 0 },{ -13, 44, 47, 4, 3, 0 },{ -14, 45, 48, 4, 3, 0 },{ -15, 46, 49, 4, 3, 0 },{ -16, 47, 50, 4, 3, 0 }, + { -16, 47, 51, 4, 3, 0 },{ -17, 48, 52, 4, 3, 0 },{ -18, 49, 53, 4, 3, 0 },{ -19, 50, 54, 4, 3, 0 },{ -20, 51, 55, 4, 3, 0 }, + { -21, 52, 56, 4, 3, 0 },{ -22, 53, 57, 4, 3, 0 },{ -23, 54, 58, 4, 3, 0 },{ -23, 54, 59, 4, 3, 0 },{ -24, 55, 60, 4, 2, 0 }, + { -25, 56, 61, 4, 2, 0 },{ -26, 57, 62, 4, 2, 0 },{ -27, 58, 63, 4, 2, 0 },{ -28, 59, 64, 4, 2, 0 },{ -29, 60, 65, 4, 2, 0 }, + { -30, 61, 66, 4, 2, 0 },{ -31, 62, 67, 4, 2, 0 },{ -32, 63, 68, 4, 2, 0 },{ -33, 64, 69, 4, 2, 0 },{ -34, 65, 70, 4, 2, 0 }, + { -35, 66, 71, 4, 2, 0 },{ -36, 67, 71, 4, 2, 0 },{ -37, 68, 72, 4, 2, 0 },{ -38, 69, 73, 4, 2, 0 },{ -39, 70, 74, 4, 2, 0 }, + { -40, 71, 74, 4, 2, 0 },{ -41, 72, 75, 4, 2, 0 },{ -42, 73, 76, 4, 2, 0 },{ -43, 74, 76, 4, 2, 0 },{ -44, 75, 77, 4, 2, 0 }, + { -45, 76, 78, 4, 2, 0 },{ -46, 77, 78, 4, 51, 0 },{ -47, 78, 79, 4, 51, 0 },{ -48, 79, 79, 4, 51, 0 },{ -49, 80, 80, 4, 51, 0 }, + { -50, 81, 80, 4, 51, 0 },{ -51, 82, 81, 4, 51, 0 },{ -52, 83, 81, 4, 51, 0 },{ -53, 84, 82, 4, 51, 0 },{ -54, 85, 82, 4, 51, 0 }, + { -55, 86, 83, 4, 51, 0 },{ -56, 87, 83, 4, 51, 0 },{ -57, 88, 84, 4, 51, 0 },{ -58, 89, 84, 4, 51, 0 },{ -59, 90, 84, 4, 50, 0 }, + { -60, 91, 85, 4, 50, 0 },{ -61, 92, 85, 4, 50, 0 },{ -62, 93, 85, 4, 50, 0 },{ -63, 94, 86, 4, 50, 0 },{ -64, 95, 86, 4, 50, 0 }, + { -65, 96, 86, 4, 50, 0 },{ -66, 97, 86, 4, 50, 0 },{ -67, 98, 87, 4, 50, 0 },{ -68, 99, 87, 4, 50, 0 },{ -69, 100, 87, 4, 50, 0 }, + { -70, 101, 87, 4, 50, 0 },{ -71, 102, 87, 4, 50, 0 },{ -72, 103, 88, 4, 50, 0 },{ -73, 104, 88, 4, 0, 0 },{ -74, 105, 88, 4, 0, 0 }, + { -75, 106, 88, 4, 0, 0 },{ -76, 107, 88, 4, 0, 0 },{ -77, 108, 88, 4, 0, 0 },{ -78, 109, 88, 4, 0, 0 },{ -79, 110, 88, 4, 0, 0 }, + { -80, 111, 88, 4, 0, 0 },}) +CREATE_VEHICLE_INFO(TrackVehicleInfoDiagUp60ToFlatLongBase1,{ + { 16, 16, 0, 12, 52, 0 },{ 17, 17, 1, 12, 52, 0 },{ 17, 17, 2, 12, 52, 0 },{ 18, 18, 3, 12, 52, 0 },{ 18, 18, 4, 12, 52, 0 }, + { 19, 19, 5, 12, 52, 0 },{ 19, 19, 6, 12, 52, 0 },{ 20, 20, 7, 12, 52, 0 },{ 20, 20, 8, 12, 52, 0 },{ 21, 21, 9, 12, 52, 0 }, + { 21, 21, 10, 12, 52, 0 },{ 22, 22, 11, 12, 52, 0 },{ 23, 23, 12, 12, 52, 0 },{ 23, 23, 13, 12, 52, 0 },{ 24, 24, 14, 12, 52, 0 }, + { 24, 24, 15, 12, 52, 0 },{ 25, 25, 16, 12, 52, 0 },{ 25, 25, 17, 12, 52, 0 },{ 26, 26, 18, 12, 52, 0 },{ 26, 26, 19, 12, 52, 0 }, + { 27, 27, 20, 12, 3, 0 },{ 28, 28, 21, 12, 3, 0 },{ 28, 28, 22, 12, 3, 0 },{ 29, 29, 23, 12, 3, 0 },{ 29, 29, 24, 12, 3, 0 }, + { 30, 30, 25, 12, 3, 0 },{ 31, 31, 26, 12, 3, 0 },{ 31, 31, 27, 12, 3, 0 },{ 32, 32, 28, 12, 3, 0 },{ 33, 33, 29, 12, 3, 0 }, + { 33, 33, 30, 12, 3, 0 },{ 34, 34, 31, 12, 3, 0 },{ 34, 34, 32, 12, 3, 0 },{ 35, 35, 33, 12, 3, 0 },{ 36, 36, 34, 12, 3, 0 }, + { 36, 36, 35, 12, 3, 0 },{ 37, 37, 36, 12, 3, 0 },{ 38, 38, 37, 12, 3, 0 },{ 39, 39, 38, 12, 3, 0 },{ 39, 39, 39, 12, 3, 0 }, + { 40, 40, 40, 12, 3, 0 },{ 41, 41, 41, 12, 3, 0 },{ 41, 41, 42, 12, 3, 0 },{ 42, 42, 43, 12, 3, 0 },{ 43, 43, 44, 12, 3, 0 }, + { 44, 44, 45, 12, 3, 0 },{ 44, 44, 46, 12, 3, 0 },{ 45, 45, 47, 12, 3, 0 },{ 46, 46, 48, 12, 3, 0 },{ 47, 47, 49, 12, 3, 0 }, + { 48, 48, 50, 12, 3, 0 },{ 48, 48, 51, 12, 3, 0 },{ 49, 49, 52, 12, 3, 0 },{ 50, 50, 53, 12, 3, 0 },{ 51, 51, 54, 12, 3, 0 }, + { 52, 52, 55, 12, 3, 0 },{ 53, 53, 56, 12, 3, 0 },{ 54, 54, 57, 12, 3, 0 },{ 55, 55, 58, 12, 3, 0 },{ 55, 55, 59, 12, 3, 0 }, + { 56, 56, 60, 12, 2, 0 },{ 57, 57, 61, 12, 2, 0 },{ 58, 58, 62, 12, 2, 0 },{ 59, 59, 63, 12, 2, 0 },{ 60, 60, 64, 12, 2, 0 }, + { 61, 61, 65, 12, 2, 0 },{ 62, 62, 66, 12, 2, 0 },{ 63, 63, 67, 12, 2, 0 },{ 64, 64, 68, 12, 2, 0 },{ 65, 65, 69, 12, 2, 0 }, + { 66, 66, 70, 12, 2, 0 },{ 67, 67, 71, 12, 2, 0 },{ 68, 68, 71, 12, 2, 0 },{ 69, 69, 72, 12, 2, 0 },{ 70, 70, 73, 12, 2, 0 }, + { 71, 71, 74, 12, 2, 0 },{ 72, 72, 74, 12, 2, 0 },{ 73, 73, 75, 12, 2, 0 },{ 74, 74, 76, 12, 2, 0 },{ 75, 75, 76, 12, 2, 0 }, + { 76, 76, 77, 12, 2, 0 },{ 77, 77, 78, 12, 2, 0 },{ 78, 78, 78, 12, 51, 0 },{ 79, 79, 79, 12, 51, 0 },{ 80, 80, 79, 12, 51, 0 }, + { 81, 81, 80, 12, 51, 0 },{ 82, 82, 80, 12, 51, 0 },{ 83, 83, 81, 12, 51, 0 },{ 84, 84, 81, 12, 51, 0 },{ 85, 85, 82, 12, 51, 0 }, + { 86, 86, 82, 12, 51, 0 },{ 87, 87, 83, 12, 51, 0 },{ 88, 88, 83, 12, 51, 0 },{ 89, 89, 84, 12, 51, 0 },{ 90, 90, 84, 12, 51, 0 }, + { 91, 91, 84, 12, 50, 0 },{ 92, 92, 85, 12, 50, 0 },{ 93, 93, 85, 12, 50, 0 },{ 94, 94, 85, 12, 50, 0 },{ 95, 95, 86, 12, 50, 0 }, + { 96, 96, 86, 12, 50, 0 },{ 97, 97, 86, 12, 50, 0 },{ 98, 98, 86, 12, 50, 0 },{ 99, 99, 87, 12, 50, 0 },{ 100, 100, 87, 12, 50, 0 }, + { 101, 101, 87, 12, 50, 0 },{ 102, 102, 87, 12, 50, 0 },{ 103, 103, 87, 12, 50, 0 },{ 104, 104, 88, 12, 50, 0 },{ 105, 105, 88, 12, 0, 0 }, + { 106, 106, 88, 12, 0, 0 },{ 107, 107, 88, 12, 0, 0 },{ 108, 108, 88, 12, 0, 0 },{ 109, 109, 88, 12, 0, 0 },{ 110, 110, 88, 12, 0, 0 }, + { 111, 111, 88, 12, 0, 0 },}) + +CREATE_VEHICLE_INFO(TrackVehicleInfoDiagUp60ToFlatLongBase2,{ + { 16, 15, 0, 20, 52, 0 },{ 17, 14, 1, 20, 52, 0 },{ 17, 14, 2, 20, 52, 0 },{ 18, 13, 3, 20, 52, 0 },{ 18, 13, 4, 20, 52, 0 }, + { 19, 12, 5, 20, 52, 0 },{ 19, 12, 6, 20, 52, 0 },{ 20, 11, 7, 20, 52, 0 },{ 20, 11, 8, 20, 52, 0 },{ 21, 10, 9, 20, 52, 0 }, + { 21, 10, 10, 20, 52, 0 },{ 22, 9, 11, 20, 52, 0 },{ 23, 8, 12, 20, 52, 0 },{ 23, 8, 13, 20, 52, 0 },{ 24, 7, 14, 20, 52, 0 }, + { 24, 7, 15, 20, 52, 0 },{ 25, 6, 16, 20, 52, 0 },{ 25, 6, 17, 20, 52, 0 },{ 26, 5, 18, 20, 52, 0 },{ 26, 5, 19, 20, 52, 0 }, + { 27, 4, 20, 20, 3, 0 },{ 28, 3, 21, 20, 3, 0 },{ 28, 3, 22, 20, 3, 0 },{ 29, 2, 23, 20, 3, 0 },{ 29, 2, 24, 20, 3, 0 }, + { 30, 1, 25, 20, 3, 0 },{ 31, 0, 26, 20, 3, 0 },{ 31, 0, 27, 20, 3, 0 },{ 32, -1, 28, 20, 3, 0 },{ 33, -2, 29, 20, 3, 0 }, + { 33, -2, 30, 20, 3, 0 },{ 34, -3, 31, 20, 3, 0 },{ 34, -3, 32, 20, 3, 0 },{ 35, -4, 33, 20, 3, 0 },{ 36, -5, 34, 20, 3, 0 }, + { 36, -5, 35, 20, 3, 0 },{ 37, -6, 36, 20, 3, 0 },{ 38, -7, 37, 20, 3, 0 },{ 39, -8, 38, 20, 3, 0 },{ 39, -8, 39, 20, 3, 0 }, + { 40, -9, 40, 20, 3, 0 },{ 41, -10, 41, 20, 3, 0 },{ 41, -10, 42, 20, 3, 0 },{ 42, -11, 43, 20, 3, 0 },{ 43, -12, 44, 20, 3, 0 }, + { 44, -13, 45, 20, 3, 0 },{ 44, -13, 46, 20, 3, 0 },{ 45, -14, 47, 20, 3, 0 },{ 46, -15, 48, 20, 3, 0 },{ 47, -16, 49, 20, 3, 0 }, + { 48, -17, 50, 20, 3, 0 },{ 48, -17, 51, 20, 3, 0 },{ 49, -18, 52, 20, 3, 0 },{ 50, -19, 53, 20, 3, 0 },{ 51, -20, 54, 20, 3, 0 }, + { 52, -21, 55, 20, 3, 0 },{ 53, -22, 56, 20, 3, 0 },{ 54, -23, 57, 20, 3, 0 },{ 55, -24, 58, 20, 3, 0 },{ 55, -24, 59, 20, 3, 0 }, + { 56, -25, 60, 20, 2, 0 },{ 57, -26, 61, 20, 2, 0 },{ 58, -27, 62, 20, 2, 0 },{ 59, -28, 63, 20, 2, 0 },{ 60, -29, 64, 20, 2, 0 }, + { 61, -30, 65, 20, 2, 0 },{ 62, -31, 66, 20, 2, 0 },{ 63, -32, 67, 20, 2, 0 },{ 64, -33, 68, 20, 2, 0 },{ 65, -34, 69, 20, 2, 0 }, + { 66, -35, 70, 20, 2, 0 },{ 67, -36, 71, 20, 2, 0 },{ 68, -37, 71, 20, 2, 0 },{ 69, -38, 72, 20, 2, 0 },{ 70, -39, 73, 20, 2, 0 }, + { 71, -40, 74, 20, 2, 0 },{ 72, -41, 74, 20, 2, 0 },{ 73, -42, 75, 20, 2, 0 },{ 74, -43, 76, 20, 2, 0 },{ 75, -44, 76, 20, 2, 0 }, + { 76, -45, 77, 20, 2, 0 },{ 77, -46, 78, 20, 2, 0 },{ 78, -47, 78, 20, 51, 0 },{ 79, -48, 79, 20, 51, 0 },{ 80, -49, 79, 20, 51, 0 }, + { 81, -50, 80, 20, 51, 0 },{ 82, -51, 80, 20, 51, 0 },{ 83, -52, 81, 20, 51, 0 },{ 84, -53, 81, 20, 51, 0 },{ 85, -54, 82, 20, 51, 0 }, + { 86, -55, 82, 20, 51, 0 },{ 87, -56, 83, 20, 51, 0 },{ 88, -57, 83, 20, 51, 0 },{ 89, -58, 84, 20, 51, 0 },{ 90, -59, 84, 20, 51, 0 }, + { 91, -60, 84, 20, 50, 0 },{ 92, -61, 85, 20, 50, 0 },{ 93, -62, 85, 20, 50, 0 },{ 94, -63, 85, 20, 50, 0 },{ 95, -64, 86, 20, 50, 0 }, + { 96, -65, 86, 20, 50, 0 },{ 97, -66, 86, 20, 50, 0 },{ 98, -67, 86, 20, 50, 0 },{ 99, -68, 87, 20, 50, 0 },{ 100, -69, 87, 20, 50, 0 }, + { 101, -70, 87, 20, 50, 0 },{ 102, -71, 87, 20, 50, 0 },{ 103, -72, 87, 20, 50, 0 },{ 104, -73, 88, 20, 50, 0 },{ 105, -74, 88, 20, 0, 0 }, + { 106, -75, 88, 20, 0, 0 },{ 107, -76, 88, 20, 0, 0 },{ 108, -77, 88, 20, 0, 0 },{ 109, -78, 88, 20, 0, 0 },{ 110, -79, 88, 20, 0, 0 }, + { 111, -80, 88, 20, 0, 0 },}) + +CREATE_VEHICLE_INFO(TrackVehicleInfoDiagUp60ToFlatLongBase3,{ + { 15, 15, 1, 28, 52, 0 },{ 15, 15, 2, 28, 52, 0 },{ 14, 14, 3, 28, 52, 0 },{ 14, 14, 4, 28, 52, 0 },{ 13, 13, 5, 28, 52, 0 }, + { 13, 13, 6, 28, 52, 0 },{ 12, 12, 7, 28, 52, 0 },{ 12, 12, 8, 28, 52, 0 },{ 11, 11, 9, 28, 52, 0 },{ 11, 11, 10, 28, 52, 0 }, + { 10, 10, 11, 28, 52, 0 },{ 9, 9, 12, 28, 52, 0 },{ 9, 9, 13, 28, 52, 0 },{ 8, 8, 14, 28, 52, 0 },{ 8, 8, 15, 28, 52, 0 }, + { 7, 7, 16, 28, 52, 0 },{ 7, 7, 17, 28, 52, 0 },{ 6, 6, 18, 28, 52, 0 },{ 6, 6, 19, 28, 52, 0 },{ 5, 5, 20, 28, 3, 0 }, + { 4, 4, 21, 28, 3, 0 },{ 4, 4, 22, 28, 3, 0 },{ 3, 3, 23, 28, 3, 0 },{ 3, 3, 24, 28, 3, 0 },{ 2, 2, 25, 28, 3, 0 }, + { 1, 1, 26, 28, 3, 0 },{ 1, 1, 27, 28, 3, 0 },{ 0, 0, 28, 28, 3, 0 },{ -1, -1, 29, 28, 3, 0 },{ -1, -1, 30, 28, 3, 0 }, + { -2, -2, 31, 28, 3, 0 },{ -2, -2, 32, 28, 3, 0 },{ -3, -3, 33, 28, 3, 0 },{ -4, -4, 34, 28, 3, 0 },{ -4, -4, 35, 28, 3, 0 }, + { -5, -5, 36, 28, 3, 0 },{ -6, -6, 37, 28, 3, 0 },{ -7, -7, 38, 28, 3, 0 },{ -7, -7, 39, 28, 3, 0 },{ -8, -8, 40, 28, 3, 0 }, + { -9, -9, 41, 28, 3, 0 },{ -9, -9, 42, 28, 3, 0 },{ -10, -10, 43, 28, 3, 0 },{ -11, -11, 44, 28, 3, 0 },{ -12, -12, 45, 28, 3, 0 }, + { -12, -12, 46, 28, 3, 0 },{ -13, -13, 47, 28, 3, 0 },{ -14, -14, 48, 28, 3, 0 },{ -15, -15, 49, 28, 3, 0 },{ -16, -16, 50, 28, 3, 0 }, + { -16, -16, 51, 28, 3, 0 },{ -17, -17, 52, 28, 3, 0 },{ -18, -18, 53, 28, 3, 0 },{ -19, -19, 54, 28, 3, 0 },{ -20, -20, 55, 28, 3, 0 }, + { -21, -21, 56, 28, 3, 0 },{ -22, -22, 57, 28, 3, 0 },{ -23, -23, 58, 28, 3, 0 },{ -23, -23, 59, 28, 3, 0 },{ -24, -24, 60, 28, 2, 0 }, + { -25, -25, 61, 28, 2, 0 },{ -26, -26, 62, 28, 2, 0 },{ -27, -27, 63, 28, 2, 0 },{ -28, -28, 64, 28, 2, 0 },{ -29, -29, 65, 28, 2, 0 }, + { -30, -30, 66, 28, 2, 0 },{ -31, -31, 67, 28, 2, 0 },{ -32, -32, 68, 28, 2, 0 },{ -33, -33, 69, 28, 2, 0 },{ -34, -34, 70, 28, 2, 0 }, + { -35, -35, 71, 28, 2, 0 },{ -36, -36, 71, 28, 2, 0 },{ -37, -37, 72, 28, 2, 0 },{ -38, -38, 73, 28, 2, 0 },{ -39, -39, 74, 28, 2, 0 }, + { -40, -40, 74, 28, 2, 0 },{ -41, -41, 75, 28, 2, 0 },{ -42, -42, 76, 28, 2, 0 },{ -43, -43, 76, 28, 2, 0 },{ -44, -44, 77, 28, 2, 0 }, + { -45, -45, 78, 28, 2, 0 },{ -46, -46, 78, 28, 51, 0 },{ -47, -47, 79, 28, 51, 0 },{ -48, -48, 79, 28, 51, 0 },{ -49, -49, 80, 28, 51, 0 }, + { -50, -50, 80, 28, 51, 0 },{ -51, -51, 81, 28, 51, 0 },{ -52, -52, 81, 28, 51, 0 },{ -53, -53, 82, 28, 51, 0 },{ -54, -54, 82, 28, 51, 0 }, + { -55, -55, 83, 28, 51, 0 },{ -56, -56, 83, 28, 51, 0 },{ -57, -57, 84, 28, 51, 0 },{ -58, -58, 84, 28, 51, 0 },{ -59, -59, 84, 28, 50, 0 }, + { -60, -60, 85, 28, 50, 0 },{ -61, -61, 85, 28, 50, 0 },{ -62, -62, 85, 28, 50, 0 },{ -63, -63, 86, 28, 50, 0 },{ -64, -64, 86, 28, 50, 0 }, + { -65, -65, 86, 28, 50, 0 },{ -66, -66, 86, 28, 50, 0 },{ -67, -67, 87, 28, 50, 0 },{ -68, -68, 87, 28, 50, 0 },{ -69, -69, 87, 28, 50, 0 }, + { -70, -70, 87, 28, 50, 0 },{ -71, -71, 87, 28, 50, 0 },{ -72, -72, 88, 28, 50, 0 },{ -73, -73, 88, 28, 0, 0 },{ -74, -74, 88, 28, 0, 0 }, + { -75, -75, 88, 28, 0, 0 },{ -76, -76, 88, 28, 0, 0 },{ -77, -77, 88, 28, 0, 0 },{ -78, -78, 88, 28, 0, 0 },{ -79, -79, 88, 28, 0, 0 }, + { -80, -80, 88, 28, 0, 0 },}) + +CREATE_VEHICLE_INFO(TrackVehicleInfoDiagFlatToDown60LongBase0,{ + { 15, 16, 8, 4, 0, 0 },{ 14, 17, 8, 4, 0, 0 },{ 13, 18, 8, 4, 0, 0 },{ 12, 19, 8, 4, 0, 0 },{ 11, 20, 8, 4, 0, 0 }, + { 10, 21, 8, 4, 0, 0 },{ 9, 22, 8, 4, 53, 0 },{ 8, 23, 7, 4, 53, 0 },{ 7, 24, 7, 4, 53, 0 },{ 6, 25, 7, 4, 53, 0 }, + { 5, 26, 7, 4, 53, 0 },{ 4, 27, 7, 4, 53, 0 },{ 3, 28, 6, 4, 53, 0 },{ 2, 29, 6, 4, 53, 0 },{ 1, 30, 6, 4, 53, 0 }, + { 0, 31, 6, 4, 53, 0 },{ -1, 32, 5, 4, 53, 0 },{ -2, 33, 5, 4, 53, 0 },{ -3, 34, 5, 4, 53, 0 },{ -4, 35, 4, 4, 53, 0 }, + { -5, 36, 4, 4, 53, 0 },{ -6, 37, 4, 4, 54, 0 },{ -7, 38, 3, 4, 54, 0 },{ -8, 39, 3, 4, 54, 0 },{ -9, 40, 2, 4, 54, 0 }, + { -10, 41, 2, 4, 54, 0 },{ -11, 42, 2, 4, 54, 0 },{ -12, 43, 1, 4, 54, 0 },{ -13, 44, 1, 4, 54, 0 },{ -14, 45, 0, 4, 54, 0 }, + { -15, 46, -1, 4, 54, 0 },{ -16, 47, -1, 4, 54, 0 },{ -17, 48, -2, 4, 54, 0 },{ -18, 49, -2, 4, 6, 0 },{ -19, 50, -3, 4, 6, 0 }, + { -20, 51, -4, 4, 6, 0 },{ -21, 52, -4, 4, 6, 0 },{ -22, 53, -5, 4, 6, 0 },{ -23, 54, -6, 4, 6, 0 },{ -24, 55, -6, 4, 6, 0 }, + { -25, 56, -7, 4, 6, 0 },{ -26, 57, -8, 4, 6, 0 },{ -27, 58, -9, 4, 6, 0 },{ -28, 59, -9, 4, 6, 0 },{ -29, 60, -10, 4, 6, 0 }, + { -30, 61, -11, 4, 6, 0 },{ -31, 62, -12, 4, 6, 0 },{ -32, 63, -13, 4, 6, 0 },{ -33, 64, -14, 4, 6, 0 },{ -34, 65, -15, 4, 6, 0 }, + { -35, 66, -16, 4, 6, 0 },{ -36, 67, -16, 4, 6, 0 },{ -37, 68, -17, 4, 6, 0 },{ -38, 69, -18, 4, 6, 0 },{ -39, 70, -19, 4, 6, 0 }, + { -40, 71, -20, 4, 6, 0 },{ -41, 72, -21, 4, 7, 0 },{ -42, 73, -22, 4, 7, 0 },{ -43, 74, -23, 4, 7, 0 },{ -44, 75, -24, 4, 7, 0 }, + { -45, 76, -25, 4, 7, 0 },{ -46, 77, -26, 4, 7, 0 },{ -47, 78, -27, 4, 7, 0 },{ -48, 79, -28, 4, 7, 0 },{ -48, 79, -29, 4, 7, 0 }, + { -49, 80, -30, 4, 7, 0 },{ -50, 81, -31, 4, 7, 0 },{ -51, 82, -32, 4, 7, 0 },{ -52, 83, -33, 4, 7, 0 },{ -52, 83, -34, 4, 7, 0 }, + { -53, 84, -35, 4, 7, 0 },{ -54, 85, -36, 4, 7, 0 },{ -55, 86, -37, 4, 7, 0 },{ -55, 86, -38, 4, 7, 0 },{ -56, 87, -39, 4, 7, 0 }, + { -57, 88, -40, 4, 7, 0 },{ -57, 88, -41, 4, 7, 0 },{ -58, 89, -42, 4, 7, 0 },{ -59, 90, -43, 4, 7, 0 },{ -59, 90, -44, 4, 7, 0 }, + { -60, 91, -45, 4, 7, 0 },{ -61, 92, -46, 4, 7, 0 },{ -61, 92, -47, 4, 7, 0 },{ -62, 93, -48, 4, 7, 0 },{ -63, 94, -49, 4, 7, 0 }, + { -63, 94, -50, 4, 7, 0 },{ -64, 95, -51, 4, 7, 0 },{ -65, 96, -52, 4, 7, 0 },{ -65, 96, -53, 4, 7, 0 },{ -66, 97, -54, 4, 7, 0 }, + { -67, 98, -55, 4, 7, 0 },{ -67, 98, -56, 4, 7, 0 },{ -68, 99, -57, 4, 7, 0 },{ -68, 99, -58, 4, 7, 0 },{ -69, 100, -59, 4, 7, 0 }, + { -70, 101, -60, 4, 55, 0 },{ -70, 101, -61, 4, 55, 0 },{ -71, 102, -62, 4, 55, 0 },{ -71, 102, -63, 4, 55, 0 },{ -72, 103, -64, 4, 55, 0 }, + { -72, 103, -65, 4, 55, 0 },{ -73, 104, -66, 4, 55, 0 },{ -73, 104, -67, 4, 55, 0 },{ -74, 105, -68, 4, 55, 0 },{ -75, 106, -69, 4, 55, 0 }, + { -75, 106, -70, 4, 55, 0 },{ -76, 107, -71, 4, 55, 0 },{ -76, 107, -72, 4, 55, 0 },{ -77, 108, -73, 4, 55, 0 },{ -77, 108, -74, 4, 55, 0 }, + { -78, 109, -75, 4, 55, 0 },{ -78, 109, -76, 4, 55, 0 },{ -79, 110, -77, 4, 55, 0 },{ -79, 110, -78, 4, 55, 0 },{ -80, 111, -79, 4, 55, 0 }, +}) + +CREATE_VEHICLE_INFO(TrackVehicleInfoDiagFlatToDown60LongBase1,{ + { 16, 16, 8, 12, 0, 0 },{ 17, 17, 8, 12, 0, 0 },{ 18, 18, 8, 12, 0, 0 },{ 19, 19, 8, 12, 0, 0 },{ 20, 20, 8, 12, 0, 0 }, + { 21, 21, 8, 12, 0, 0 },{ 22, 22, 8, 12, 0, 0 },{ 23, 23, 8, 12, 53, 0 },{ 24, 24, 7, 12, 53, 0 },{ 25, 25, 7, 12, 53, 0 }, + { 26, 26, 7, 12, 53, 0 },{ 27, 27, 7, 12, 53, 0 },{ 28, 28, 7, 12, 53, 0 },{ 29, 29, 6, 12, 53, 0 },{ 30, 30, 6, 12, 53, 0 }, + { 31, 31, 6, 12, 53, 0 },{ 32, 32, 6, 12, 53, 0 },{ 33, 33, 5, 12, 53, 0 },{ 34, 34, 5, 12, 53, 0 },{ 35, 35, 5, 12, 53, 0 }, + { 36, 36, 4, 12, 53, 0 },{ 37, 37, 4, 12, 53, 0 },{ 38, 38, 4, 12, 54, 0 },{ 39, 39, 3, 12, 54, 0 },{ 40, 40, 3, 12, 54, 0 }, + { 41, 41, 2, 12, 54, 0 },{ 42, 42, 2, 12, 54, 0 },{ 43, 43, 2, 12, 54, 0 },{ 44, 44, 1, 12, 54, 0 },{ 45, 45, 1, 12, 54, 0 }, + { 46, 46, 0, 12, 54, 0 },{ 47, 47, -1, 12, 54, 0 },{ 48, 48, -1, 12, 54, 0 },{ 49, 49, -2, 12, 54, 0 },{ 50, 50, -2, 12, 6, 0 }, + { 51, 51, -3, 12, 6, 0 },{ 52, 52, -4, 12, 6, 0 },{ 53, 53, -4, 12, 6, 0 },{ 54, 54, -5, 12, 6, 0 },{ 55, 55, -6, 12, 6, 0 }, + { 56, 56, -6, 12, 6, 0 },{ 57, 57, -7, 12, 6, 0 },{ 58, 58, -8, 12, 6, 0 },{ 59, 59, -9, 12, 6, 0 },{ 60, 60, -9, 12, 6, 0 }, + { 61, 61, -10, 12, 6, 0 },{ 62, 62, -11, 12, 6, 0 },{ 63, 63, -12, 12, 6, 0 },{ 64, 64, -13, 12, 6, 0 },{ 65, 65, -14, 12, 6, 0 }, + { 66, 66, -15, 12, 6, 0 },{ 67, 67, -16, 12, 6, 0 },{ 68, 68, -16, 12, 6, 0 },{ 69, 69, -17, 12, 6, 0 },{ 70, 70, -18, 12, 6, 0 }, + { 71, 71, -19, 12, 6, 0 },{ 72, 72, -20, 12, 6, 0 },{ 73, 73, -21, 12, 7, 0 },{ 74, 74, -22, 12, 7, 0 },{ 75, 75, -23, 12, 7, 0 }, + { 76, 76, -24, 12, 7, 0 },{ 77, 77, -25, 12, 7, 0 },{ 78, 78, -26, 12, 7, 0 },{ 79, 79, -27, 12, 7, 0 },{ 80, 80, -28, 12, 7, 0 }, + { 80, 80, -29, 12, 7, 0 },{ 81, 81, -30, 12, 7, 0 },{ 82, 82, -31, 12, 7, 0 },{ 83, 83, -32, 12, 7, 0 },{ 84, 84, -33, 12, 7, 0 }, + { 84, 84, -34, 12, 7, 0 },{ 85, 85, -35, 12, 7, 0 },{ 86, 86, -36, 12, 7, 0 },{ 87, 87, -37, 12, 7, 0 },{ 87, 87, -38, 12, 7, 0 }, + { 88, 88, -39, 12, 7, 0 },{ 89, 89, -40, 12, 7, 0 },{ 89, 89, -41, 12, 7, 0 },{ 90, 90, -42, 12, 7, 0 },{ 91, 91, -43, 12, 7, 0 }, + { 91, 91, -44, 12, 7, 0 },{ 92, 92, -45, 12, 7, 0 },{ 93, 93, -46, 12, 7, 0 },{ 93, 93, -47, 12, 7, 0 },{ 94, 94, -48, 12, 7, 0 }, + { 95, 95, -49, 12, 7, 0 },{ 95, 95, -50, 12, 7, 0 },{ 96, 96, -51, 12, 7, 0 },{ 97, 97, -52, 12, 7, 0 },{ 97, 97, -53, 12, 7, 0 }, + { 98, 98, -54, 12, 7, 0 },{ 99, 99, -55, 12, 7, 0 },{ 99, 99, -56, 12, 7, 0 },{ 100, 100, -57, 12, 7, 0 },{ 100, 100, -58, 12, 7, 0 }, + { 101, 101, -59, 12, 7, 0 },{ 102, 102, -60, 12, 55, 0 },{ 102, 102, -61, 12, 55, 0 },{ 103, 103, -62, 12, 55, 0 },{ 103, 103, -63, 12, 55, 0 }, + { 104, 104, -64, 12, 55, 0 },{ 104, 104, -65, 12, 55, 0 },{ 105, 105, -66, 12, 55, 0 },{ 105, 105, -67, 12, 55, 0 },{ 106, 106, -68, 12, 55, 0 }, + { 107, 107, -69, 12, 55, 0 },{ 107, 107, -70, 12, 55, 0 },{ 108, 108, -71, 12, 55, 0 },{ 108, 108, -72, 12, 55, 0 },{ 109, 109, -73, 12, 55, 0 }, + { 109, 109, -74, 12, 55, 0 },{ 110, 110, -75, 12, 55, 0 },{ 110, 110, -76, 12, 55, 0 },{ 111, 111, -77, 12, 55, 0 },{ 111, 111, -78, 12, 55, 0 }, + { 112, 112, -79, 12, 55, 0 },{ 112, 112, -80, 12, 55, 0 },}) + +CREATE_VEHICLE_INFO(TrackVehicleInfoDiagFlatToDown60LongBase2,{ + { 16, 15, 8, 20, 0, 0 },{ 17, 14, 8, 20, 0, 0 },{ 18, 13, 8, 20, 0, 0 },{ 19, 12, 8, 20, 0, 0 },{ 20, 11, 8, 20, 0, 0 }, + { 21, 10, 8, 20, 0, 0 },{ 22, 9, 8, 20, 0, 0 },{ 23, 8, 8, 20, 53, 0 },{ 24, 7, 7, 20, 53, 0 },{ 25, 6, 7, 20, 53, 0 }, + { 26, 5, 7, 20, 53, 0 },{ 27, 4, 7, 20, 53, 0 },{ 28, 3, 7, 20, 53, 0 },{ 29, 2, 6, 20, 53, 0 },{ 30, 1, 6, 20, 53, 0 }, + { 31, 0, 6, 20, 53, 0 },{ 32, -1, 6, 20, 53, 0 },{ 33, -2, 5, 20, 53, 0 },{ 34, -3, 5, 20, 53, 0 },{ 35, -4, 5, 20, 53, 0 }, + { 36, -5, 4, 20, 53, 0 },{ 37, -6, 4, 20, 53, 0 },{ 38, -7, 4, 20, 54, 0 },{ 39, -8, 3, 20, 54, 0 },{ 40, -9, 3, 20, 54, 0 }, + { 41, -10, 2, 20, 54, 0 },{ 42, -11, 2, 20, 54, 0 },{ 43, -12, 2, 20, 54, 0 },{ 44, -13, 1, 20, 54, 0 },{ 45, -14, 1, 20, 54, 0 }, + { 46, -15, 0, 20, 54, 0 },{ 47, -16, -1, 20, 54, 0 },{ 48, -17, -1, 20, 54, 0 },{ 49, -18, -2, 20, 54, 0 },{ 50, -19, -2, 20, 6, 0 }, + { 51, -20, -3, 20, 6, 0 },{ 52, -21, -4, 20, 6, 0 },{ 53, -22, -4, 20, 6, 0 },{ 54, -23, -5, 20, 6, 0 },{ 55, -24, -6, 20, 6, 0 }, + { 56, -25, -6, 20, 6, 0 },{ 57, -26, -7, 20, 6, 0 },{ 58, -27, -8, 20, 6, 0 },{ 59, -28, -9, 20, 6, 0 },{ 60, -29, -9, 20, 6, 0 }, + { 61, -30, -10, 20, 6, 0 },{ 62, -31, -11, 20, 6, 0 },{ 63, -32, -12, 20, 6, 0 },{ 64, -33, -13, 20, 6, 0 },{ 65, -34, -14, 20, 6, 0 }, + { 66, -35, -15, 20, 6, 0 },{ 67, -36, -16, 20, 6, 0 },{ 68, -37, -16, 20, 6, 0 },{ 69, -38, -17, 20, 6, 0 },{ 70, -39, -18, 20, 6, 0 }, + { 71, -40, -19, 20, 6, 0 },{ 72, -41, -20, 20, 6, 0 },{ 73, -42, -21, 20, 7, 0 },{ 74, -43, -22, 20, 7, 0 },{ 75, -44, -23, 20, 7, 0 }, + { 76, -45, -24, 20, 7, 0 },{ 77, -46, -25, 20, 7, 0 },{ 78, -47, -26, 20, 7, 0 },{ 79, -48, -27, 20, 7, 0 },{ 80, -49, -28, 20, 7, 0 }, + { 80, -49, -29, 20, 7, 0 },{ 81, -50, -30, 20, 7, 0 },{ 82, -51, -31, 20, 7, 0 },{ 83, -52, -32, 20, 7, 0 },{ 84, -53, -33, 20, 7, 0 }, + { 84, -53, -34, 20, 7, 0 },{ 85, -54, -35, 20, 7, 0 },{ 86, -55, -36, 20, 7, 0 },{ 87, -56, -37, 20, 7, 0 },{ 87, -56, -38, 20, 7, 0 }, + { 88, -57, -39, 20, 7, 0 },{ 89, -58, -40, 20, 7, 0 },{ 89, -58, -41, 20, 7, 0 },{ 90, -59, -42, 20, 7, 0 },{ 91, -60, -43, 20, 7, 0 }, + { 91, -60, -44, 20, 7, 0 },{ 92, -61, -45, 20, 7, 0 },{ 93, -62, -46, 20, 7, 0 },{ 93, -62, -47, 20, 7, 0 },{ 94, -63, -48, 20, 7, 0 }, + { 95, -64, -49, 20, 7, 0 },{ 95, -64, -50, 20, 7, 0 },{ 96, -65, -51, 20, 7, 0 },{ 97, -66, -52, 20, 7, 0 },{ 97, -66, -53, 20, 7, 0 }, + { 98, -67, -54, 20, 7, 0 },{ 99, -68, -55, 20, 7, 0 },{ 99, -68, -56, 20, 7, 0 },{ 100, -69, -57, 20, 7, 0 },{ 100, -69, -58, 20, 7, 0 }, + { 101, -70, -59, 20, 7, 0 },{ 102, -71, -60, 20, 55, 0 },{ 102, -71, -61, 20, 55, 0 },{ 103, -72, -62, 20, 55, 0 },{ 103, -72, -63, 20, 55, 0 }, + { 104, -73, -64, 20, 55, 0 },{ 104, -73, -65, 20, 55, 0 },{ 105, -74, -66, 20, 55, 0 },{ 105, -74, -67, 20, 55, 0 },{ 106, -75, -68, 20, 55, 0 }, + { 107, -76, -69, 20, 55, 0 },{ 107, -76, -70, 20, 55, 0 },{ 108, -77, -71, 20, 55, 0 },{ 108, -77, -72, 20, 55, 0 },{ 109, -78, -73, 20, 55, 0 }, + { 109, -78, -74, 20, 55, 0 },{ 110, -79, -75, 20, 55, 0 },{ 110, -79, -76, 20, 55, 0 },{ 111, -80, -77, 20, 55, 0 },{ 111, -80, -78, 20, 55, 0 }, + { 112, -81, -79, 20, 55, 0 },{ 112, -81, -80, 20, 55, 0 },}) + +CREATE_VEHICLE_INFO(TrackVehicleInfoDiagFlatToDown60LongBase3,{ + { 15, 15, 8, 28, 0, 0 },{ 14, 14, 8, 28, 0, 0 },{ 13, 13, 8, 28, 0, 0 },{ 12, 12, 8, 28, 0, 0 },{ 11, 11, 8, 28, 0, 0 }, + { 10, 10, 8, 28, 0, 0 },{ 9, 9, 8, 28, 53, 0 },{ 8, 8, 7, 28, 53, 0 },{ 7, 7, 7, 28, 53, 0 },{ 6, 6, 7, 28, 53, 0 }, + { 5, 5, 7, 28, 53, 0 },{ 4, 4, 7, 28, 53, 0 },{ 3, 3, 6, 28, 53, 0 },{ 2, 2, 6, 28, 53, 0 },{ 1, 1, 6, 28, 53, 0 }, + { 0, 0, 6, 28, 53, 0 },{ -1, -1, 5, 28, 53, 0 },{ -2, -2, 5, 28, 53, 0 },{ -3, -3, 5, 28, 53, 0 },{ -4, -4, 4, 28, 53, 0 }, + { -5, -5, 4, 28, 53, 0 },{ -6, -6, 4, 28, 54, 0 },{ -7, -7, 3, 28, 54, 0 },{ -8, -8, 3, 28, 54, 0 },{ -9, -9, 2, 28, 54, 0 }, + { -10, -10, 2, 28, 54, 0 },{ -11, -11, 2, 28, 54, 0 },{ -12, -12, 1, 28, 54, 0 },{ -13, -13, 1, 28, 54, 0 },{ -14, -14, 0, 28, 54, 0 }, + { -15, -15, -1, 28, 54, 0 },{ -16, -16, -1, 28, 54, 0 },{ -17, -17, -2, 28, 54, 0 },{ -18, -18, -2, 28, 6, 0 },{ -19, -19, -3, 28, 6, 0 }, + { -20, -20, -4, 28, 6, 0 },{ -21, -21, -4, 28, 6, 0 },{ -22, -22, -5, 28, 6, 0 },{ -23, -23, -6, 28, 6, 0 },{ -24, -24, -6, 28, 6, 0 }, + { -25, -25, -7, 28, 6, 0 },{ -26, -26, -8, 28, 6, 0 },{ -27, -27, -9, 28, 6, 0 },{ -28, -28, -9, 28, 6, 0 },{ -29, -29, -10, 28, 6, 0 }, + { -30, -30, -11, 28, 6, 0 },{ -31, -31, -12, 28, 6, 0 },{ -32, -32, -13, 28, 6, 0 },{ -33, -33, -14, 28, 6, 0 },{ -34, -34, -15, 28, 6, 0 }, + { -35, -35, -16, 28, 6, 0 },{ -36, -36, -16, 28, 6, 0 },{ -37, -37, -17, 28, 6, 0 },{ -38, -38, -18, 28, 6, 0 },{ -39, -39, -19, 28, 6, 0 }, + { -40, -40, -20, 28, 6, 0 },{ -41, -41, -21, 28, 7, 0 },{ -42, -42, -22, 28, 7, 0 },{ -43, -43, -23, 28, 7, 0 },{ -44, -44, -24, 28, 7, 0 }, + { -45, -45, -25, 28, 7, 0 },{ -46, -46, -26, 28, 7, 0 },{ -47, -47, -27, 28, 7, 0 },{ -48, -48, -28, 28, 7, 0 },{ -48, -48, -29, 28, 7, 0 }, + { -49, -49, -30, 28, 7, 0 },{ -50, -50, -31, 28, 7, 0 },{ -51, -51, -32, 28, 7, 0 },{ -52, -52, -33, 28, 7, 0 },{ -52, -52, -34, 28, 7, 0 }, + { -53, -53, -35, 28, 7, 0 },{ -54, -54, -36, 28, 7, 0 },{ -55, -55, -37, 28, 7, 0 },{ -55, -55, -38, 28, 7, 0 },{ -56, -56, -39, 28, 7, 0 }, + { -57, -57, -40, 28, 7, 0 },{ -57, -57, -41, 28, 7, 0 },{ -58, -58, -42, 28, 7, 0 },{ -59, -59, -43, 28, 7, 0 },{ -59, -59, -44, 28, 7, 0 }, + { -60, -60, -45, 28, 7, 0 },{ -61, -61, -46, 28, 7, 0 },{ -61, -61, -47, 28, 7, 0 },{ -62, -62, -48, 28, 7, 0 },{ -63, -63, -49, 28, 7, 0 }, + { -63, -63, -50, 28, 7, 0 },{ -64, -64, -51, 28, 7, 0 },{ -65, -65, -52, 28, 7, 0 },{ -65, -65, -53, 28, 7, 0 },{ -66, -66, -54, 28, 7, 0 }, + { -67, -67, -55, 28, 7, 0 },{ -67, -67, -56, 28, 7, 0 },{ -68, -68, -57, 28, 7, 0 },{ -68, -68, -58, 28, 7, 0 },{ -69, -69, -59, 28, 7, 0 }, + { -70, -70, -60, 28, 55, 0 },{ -70, -70, -61, 28, 55, 0 },{ -71, -71, -62, 28, 55, 0 },{ -71, -71, -63, 28, 55, 0 },{ -72, -72, -64, 28, 55, 0 }, + { -72, -72, -65, 28, 55, 0 },{ -73, -73, -66, 28, 55, 0 },{ -73, -73, -67, 28, 55, 0 },{ -74, -74, -68, 28, 55, 0 },{ -75, -75, -69, 28, 55, 0 }, + { -75, -75, -70, 28, 55, 0 },{ -76, -76, -71, 28, 55, 0 },{ -76, -76, -72, 28, 55, 0 },{ -77, -77, -73, 28, 55, 0 },{ -77, -77, -74, 28, 55, 0 }, + { -78, -78, -75, 28, 55, 0 },{ -78, -78, -76, 28, 55, 0 },{ -79, -79, -77, 28, 55, 0 },{ -79, -79, -78, 28, 55, 0 },{ -80, -80, -79, 28, 55, 0 }, +}) + +CREATE_VEHICLE_INFO(TrackVehicleInfoDiagDown60ToFlatLongBase0,{ + { 15, 16, 47, 4, 55, 0 },{ 15, 16, 46, 4, 55, 0 },{ 14, 17, 45, 4, 55, 0 },{ 14, 17, 44, 4, 55, 0 },{ 13, 18, 43, 4, 55, 0 }, + { 13, 18, 42, 4, 55, 0 },{ 12, 19, 41, 4, 55, 0 },{ 12, 19, 40, 4, 55, 0 },{ 11, 20, 39, 4, 55, 0 },{ 11, 20, 38, 4, 55, 0 }, + { 10, 21, 37, 4, 55, 0 },{ 9, 22, 36, 4, 55, 0 },{ 9, 22, 35, 4, 55, 0 },{ 8, 23, 34, 4, 55, 0 },{ 8, 23, 33, 4, 55, 0 }, + { 7, 24, 32, 4, 55, 0 },{ 7, 24, 31, 4, 55, 0 },{ 6, 25, 30, 4, 55, 0 },{ 6, 25, 29, 4, 55, 0 },{ 5, 26, 28, 4, 7, 0 }, + { 4, 27, 27, 4, 7, 0 },{ 4, 27, 26, 4, 7, 0 },{ 3, 28, 25, 4, 7, 0 },{ 3, 28, 24, 4, 7, 0 },{ 2, 29, 23, 4, 7, 0 }, + { 1, 30, 22, 4, 7, 0 },{ 1, 30, 21, 4, 7, 0 },{ 0, 31, 20, 4, 7, 0 },{ -1, 32, 19, 4, 7, 0 },{ -1, 32, 18, 4, 7, 0 }, + { -2, 33, 17, 4, 7, 0 },{ -2, 33, 16, 4, 7, 0 },{ -3, 34, 15, 4, 7, 0 },{ -4, 35, 14, 4, 7, 0 },{ -4, 35, 13, 4, 7, 0 }, + { -5, 36, 12, 4, 7, 0 },{ -6, 37, 11, 4, 7, 0 },{ -7, 38, 10, 4, 7, 0 },{ -7, 38, 9, 4, 7, 0 },{ -8, 39, 8, 4, 7, 0 }, + { -9, 40, 7, 4, 7, 0 },{ -9, 40, 6, 4, 7, 0 },{ -10, 41, 5, 4, 7, 0 },{ -11, 42, 4, 4, 7, 0 },{ -12, 43, 3, 4, 7, 0 }, + { -12, 43, 2, 4, 7, 0 },{ -13, 44, 1, 4, 7, 0 },{ -14, 45, 0, 4, 7, 0 },{ -15, 46, -1, 4, 7, 0 },{ -16, 47, -2, 4, 7, 0 }, + { -16, 47, -3, 4, 7, 0 },{ -17, 48, -4, 4, 7, 0 },{ -18, 49, -5, 4, 7, 0 },{ -19, 50, -6, 4, 7, 0 },{ -20, 51, -7, 4, 7, 0 }, + { -21, 52, -8, 4, 7, 0 },{ -22, 53, -9, 4, 7, 0 },{ -23, 54, -10, 4, 7, 0 },{ -23, 54, -11, 4, 7, 0 },{ -24, 55, -12, 4, 6, 0 }, + { -25, 56, -13, 4, 6, 0 },{ -26, 57, -14, 4, 6, 0 },{ -27, 58, -15, 4, 6, 0 },{ -28, 59, -16, 4, 6, 0 },{ -29, 60, -17, 4, 6, 0 }, + { -30, 61, -18, 4, 6, 0 },{ -31, 62, -19, 4, 6, 0 },{ -32, 63, -20, 4, 6, 0 },{ -33, 64, -21, 4, 6, 0 },{ -34, 65, -22, 4, 6, 0 }, + { -35, 66, -23, 4, 6, 0 },{ -36, 67, -23, 4, 6, 0 },{ -37, 68, -24, 4, 6, 0 },{ -38, 69, -25, 4, 6, 0 },{ -39, 70, -26, 4, 6, 0 }, + { -40, 71, -26, 4, 6, 0 },{ -41, 72, -27, 4, 6, 0 },{ -42, 73, -28, 4, 6, 0 },{ -43, 74, -28, 4, 6, 0 },{ -44, 75, -29, 4, 6, 0 }, + { -45, 76, -30, 4, 6, 0 },{ -46, 77, -30, 4, 54, 0 },{ -47, 78, -31, 4, 54, 0 },{ -48, 79, -31, 4, 54, 0 },{ -49, 80, -32, 4, 54, 0 }, + { -50, 81, -32, 4, 54, 0 },{ -51, 82, -33, 4, 54, 0 },{ -52, 83, -33, 4, 54, 0 },{ -53, 84, -34, 4, 54, 0 },{ -54, 85, -34, 4, 54, 0 }, + { -55, 86, -35, 4, 54, 0 },{ -56, 87, -35, 4, 54, 0 },{ -57, 88, -36, 4, 54, 0 },{ -58, 89, -36, 4, 54, 0 },{ -59, 90, -36, 4, 53, 0 }, + { -60, 91, -37, 4, 53, 0 },{ -61, 92, -37, 4, 53, 0 },{ -62, 93, -37, 4, 53, 0 },{ -63, 94, -38, 4, 53, 0 },{ -64, 95, -38, 4, 53, 0 }, + { -65, 96, -38, 4, 53, 0 },{ -66, 97, -38, 4, 53, 0 },{ -67, 98, -39, 4, 53, 0 },{ -68, 99, -39, 4, 53, 0 },{ -69, 100, -39, 4, 53, 0 }, + { -70, 101, -39, 4, 53, 0 },{ -71, 102, -39, 4, 53, 0 },{ -72, 103, -40, 4, 53, 0 },{ -73, 104, -40, 4, 0, 0 },{ -74, 105, -40, 4, 0, 0 }, + { -75, 106, -40, 4, 0, 0 },{ -76, 107, -40, 4, 0, 0 },{ -77, 108, -40, 4, 0, 0 },{ -78, 109, -40, 4, 0, 0 },{ -79, 110, -40, 4, 0, 0 }, +}) + +CREATE_VEHICLE_INFO(TrackVehicleInfoDiagDown60ToFlatLongBase1,{ + { 16, 16, 48, 12, 55, 0 },{ 17, 17, 47, 12, 55, 0 },{ 17, 17, 46, 12, 55, 0 },{ 18, 18, 45, 12, 55, 0 },{ 18, 18, 44, 12, 55, 0 }, + { 19, 19, 43, 12, 55, 0 },{ 19, 19, 42, 12, 55, 0 },{ 20, 20, 41, 12, 55, 0 },{ 20, 20, 40, 12, 55, 0 },{ 21, 21, 39, 12, 55, 0 }, + { 21, 21, 38, 12, 55, 0 },{ 22, 22, 37, 12, 55, 0 },{ 23, 23, 36, 12, 55, 0 },{ 23, 23, 35, 12, 55, 0 },{ 24, 24, 34, 12, 55, 0 }, + { 24, 24, 33, 12, 55, 0 },{ 25, 25, 32, 12, 55, 0 },{ 25, 25, 31, 12, 55, 0 },{ 26, 26, 30, 12, 55, 0 },{ 26, 26, 29, 12, 55, 0 }, + { 27, 27, 28, 12, 7, 0 },{ 28, 28, 27, 12, 7, 0 },{ 28, 28, 26, 12, 7, 0 },{ 29, 29, 25, 12, 7, 0 },{ 29, 29, 24, 12, 7, 0 }, + { 30, 30, 23, 12, 7, 0 },{ 31, 31, 22, 12, 7, 0 },{ 31, 31, 21, 12, 7, 0 },{ 32, 32, 20, 12, 7, 0 },{ 33, 33, 19, 12, 7, 0 }, + { 33, 33, 18, 12, 7, 0 },{ 34, 34, 17, 12, 7, 0 },{ 34, 34, 16, 12, 7, 0 },{ 35, 35, 15, 12, 7, 0 },{ 36, 36, 14, 12, 7, 0 }, + { 36, 36, 13, 12, 7, 0 },{ 37, 37, 12, 12, 7, 0 },{ 38, 38, 11, 12, 7, 0 },{ 39, 39, 10, 12, 7, 0 },{ 39, 39, 9, 12, 7, 0 }, + { 40, 40, 8, 12, 7, 0 },{ 41, 41, 7, 12, 7, 0 },{ 41, 41, 6, 12, 7, 0 },{ 42, 42, 5, 12, 7, 0 },{ 43, 43, 4, 12, 7, 0 }, + { 44, 44, 3, 12, 7, 0 },{ 44, 44, 2, 12, 7, 0 },{ 45, 45, 1, 12, 7, 0 },{ 46, 46, 0, 12, 7, 0 },{ 47, 47, -1, 12, 7, 0 }, + { 48, 48, -2, 12, 7, 0 },{ 48, 48, -3, 12, 7, 0 },{ 49, 49, -4, 12, 7, 0 },{ 50, 50, -5, 12, 7, 0 },{ 51, 51, -6, 12, 7, 0 }, + { 52, 52, -7, 12, 7, 0 },{ 53, 53, -8, 12, 7, 0 },{ 54, 54, -9, 12, 7, 0 },{ 55, 55, -10, 12, 7, 0 },{ 55, 55, -11, 12, 7, 0 }, + { 56, 56, -12, 12, 6, 0 },{ 57, 57, -13, 12, 6, 0 },{ 58, 58, -14, 12, 6, 0 },{ 59, 59, -15, 12, 6, 0 },{ 60, 60, -16, 12, 6, 0 }, + { 61, 61, -17, 12, 6, 0 },{ 62, 62, -18, 12, 6, 0 },{ 63, 63, -19, 12, 6, 0 },{ 64, 64, -20, 12, 6, 0 },{ 65, 65, -21, 12, 6, 0 }, + { 66, 66, -22, 12, 6, 0 },{ 67, 67, -23, 12, 6, 0 },{ 68, 68, -23, 12, 6, 0 },{ 69, 69, -24, 12, 6, 0 },{ 70, 70, -25, 12, 6, 0 }, + { 71, 71, -26, 12, 6, 0 },{ 72, 72, -26, 12, 6, 0 },{ 73, 73, -27, 12, 6, 0 },{ 74, 74, -28, 12, 6, 0 },{ 75, 75, -28, 12, 6, 0 }, + { 76, 76, -29, 12, 6, 0 },{ 77, 77, -30, 12, 6, 0 },{ 78, 78, -30, 12, 54, 0 },{ 79, 79, -31, 12, 54, 0 },{ 80, 80, -31, 12, 54, 0 }, + { 81, 81, -32, 12, 54, 0 },{ 82, 82, -32, 12, 54, 0 },{ 83, 83, -33, 12, 54, 0 },{ 84, 84, -33, 12, 54, 0 },{ 85, 85, -34, 12, 54, 0 }, + { 86, 86, -34, 12, 54, 0 },{ 87, 87, -35, 12, 54, 0 },{ 88, 88, -35, 12, 54, 0 },{ 89, 89, -36, 12, 54, 0 },{ 90, 90, -36, 12, 54, 0 }, + { 91, 91, -36, 12, 53, 0 },{ 92, 92, -37, 12, 53, 0 },{ 93, 93, -37, 12, 53, 0 },{ 94, 94, -37, 12, 53, 0 },{ 95, 95, -38, 12, 53, 0 }, + { 96, 96, -38, 12, 53, 0 },{ 97, 97, -38, 12, 53, 0 },{ 98, 98, -38, 12, 53, 0 },{ 99, 99, -39, 12, 53, 0 },{ 100, 100, -39, 12, 53, 0 }, + { 101, 101, -39, 12, 53, 0 },{ 102, 102, -39, 12, 53, 0 },{ 103, 103, -39, 12, 53, 0 },{ 104, 104, -40, 12, 53, 0 },{ 105, 105, -40, 12, 0, 0 }, + { 106, 106, -40, 12, 0, 0 },{ 107, 107, -40, 12, 0, 0 },{ 108, 108, -40, 12, 0, 0 },{ 109, 109, -40, 12, 0, 0 },{ 110, 110, -40, 12, 0, 0 }, + { 111, 111, -40, 12, 0, 0 },{ 112, 112, -40, 12, 0, 0 },}) + +CREATE_VEHICLE_INFO(TrackVehicleInfoDiagDown60ToFlatLongBase2,{ + { 16, 15, 48, 20, 55, 0 },{ 17, 14, 47, 20, 55, 0 },{ 17, 14, 46, 20, 55, 0 },{ 18, 13, 45, 20, 55, 0 },{ 18, 13, 44, 20, 55, 0 }, + { 19, 12, 43, 20, 55, 0 },{ 19, 12, 42, 20, 55, 0 },{ 20, 11, 41, 20, 55, 0 },{ 20, 11, 40, 20, 55, 0 },{ 21, 10, 39, 20, 55, 0 }, + { 21, 10, 38, 20, 55, 0 },{ 22, 9, 37, 20, 55, 0 },{ 23, 8, 36, 20, 55, 0 },{ 23, 8, 35, 20, 55, 0 },{ 24, 7, 34, 20, 55, 0 }, + { 24, 7, 33, 20, 55, 0 },{ 25, 6, 32, 20, 55, 0 },{ 25, 6, 31, 20, 55, 0 },{ 26, 5, 30, 20, 55, 0 },{ 26, 5, 29, 20, 55, 0 }, + { 27, 4, 28, 20, 7, 0 },{ 28, 3, 27, 20, 7, 0 },{ 28, 3, 26, 20, 7, 0 },{ 29, 2, 25, 20, 7, 0 },{ 29, 2, 24, 20, 7, 0 }, + { 30, 1, 23, 20, 7, 0 },{ 31, 0, 22, 20, 7, 0 },{ 31, 0, 21, 20, 7, 0 },{ 32, -1, 20, 20, 7, 0 },{ 33, -2, 19, 20, 7, 0 }, + { 33, -2, 18, 20, 7, 0 },{ 34, -3, 17, 20, 7, 0 },{ 34, -3, 16, 20, 7, 0 },{ 35, -4, 15, 20, 7, 0 },{ 36, -5, 14, 20, 7, 0 }, + { 36, -5, 13, 20, 7, 0 },{ 37, -6, 12, 20, 7, 0 },{ 38, -7, 11, 20, 7, 0 },{ 39, -8, 10, 20, 7, 0 },{ 39, -8, 9, 20, 7, 0 }, + { 40, -9, 8, 20, 7, 0 },{ 41, -10, 7, 20, 7, 0 },{ 41, -10, 6, 20, 7, 0 },{ 42, -11, 5, 20, 7, 0 },{ 43, -12, 4, 20, 7, 0 }, + { 44, -13, 3, 20, 7, 0 },{ 44, -13, 2, 20, 7, 0 },{ 45, -14, 1, 20, 7, 0 },{ 46, -15, 0, 20, 7, 0 },{ 47, -16, -1, 20, 7, 0 }, + { 48, -17, -2, 20, 7, 0 },{ 48, -17, -3, 20, 7, 0 },{ 49, -18, -4, 20, 7, 0 },{ 50, -19, -5, 20, 7, 0 },{ 51, -20, -6, 20, 7, 0 }, + { 52, -21, -7, 20, 7, 0 },{ 53, -22, -8, 20, 7, 0 },{ 54, -23, -9, 20, 7, 0 },{ 55, -24, -10, 20, 7, 0 },{ 55, -24, -11, 20, 7, 0 }, + { 56, -25, -12, 20, 6, 0 },{ 57, -26, -13, 20, 6, 0 },{ 58, -27, -14, 20, 6, 0 },{ 59, -28, -15, 20, 6, 0 },{ 60, -29, -16, 20, 6, 0 }, + { 61, -30, -17, 20, 6, 0 },{ 62, -31, -18, 20, 6, 0 },{ 63, -32, -19, 20, 6, 0 },{ 64, -33, -20, 20, 6, 0 },{ 65, -34, -21, 20, 6, 0 }, + { 66, -35, -22, 20, 6, 0 },{ 67, -36, -23, 20, 6, 0 },{ 68, -37, -23, 20, 6, 0 },{ 69, -38, -24, 20, 6, 0 },{ 70, -39, -25, 20, 6, 0 }, + { 71, -40, -26, 20, 6, 0 },{ 72, -41, -26, 20, 6, 0 },{ 73, -42, -27, 20, 6, 0 },{ 74, -43, -28, 20, 6, 0 },{ 75, -44, -28, 20, 6, 0 }, + { 76, -45, -29, 20, 6, 0 },{ 77, -46, -30, 20, 6, 0 },{ 78, -47, -30, 20, 54, 0 },{ 79, -48, -31, 20, 54, 0 },{ 80, -49, -31, 20, 54, 0 }, + { 81, -50, -32, 20, 54, 0 },{ 82, -51, -32, 20, 54, 0 },{ 83, -52, -33, 20, 54, 0 },{ 84, -53, -33, 20, 54, 0 },{ 85, -54, -34, 20, 54, 0 }, + { 86, -55, -34, 20, 54, 0 },{ 87, -56, -35, 20, 54, 0 },{ 88, -57, -35, 20, 54, 0 },{ 89, -58, -36, 20, 54, 0 },{ 90, -59, -36, 20, 54, 0 }, + { 91, -60, -36, 20, 53, 0 },{ 92, -61, -37, 20, 53, 0 },{ 93, -62, -37, 20, 53, 0 },{ 94, -63, -37, 20, 53, 0 },{ 95, -64, -38, 20, 53, 0 }, + { 96, -65, -38, 20, 53, 0 },{ 97, -66, -38, 20, 53, 0 },{ 98, -67, -38, 20, 53, 0 },{ 99, -68, -39, 20, 53, 0 },{ 100, -69, -39, 20, 53, 0 }, + { 101, -70, -39, 20, 53, 0 },{ 102, -71, -39, 20, 53, 0 },{ 103, -72, -39, 20, 53, 0 },{ 104, -73, -40, 20, 53, 0 },{ 105, -74, -40, 20, 0, 0 }, + { 106, -75, -40, 20, 0, 0 },{ 107, -76, -40, 20, 0, 0 },{ 108, -77, -40, 20, 0, 0 },{ 109, -78, -40, 20, 0, 0 },{ 110, -79, -40, 20, 0, 0 }, + { 111, -80, -40, 20, 0, 0 },{ 112, -81, -40, 20, 0, 0 },}) + +CREATE_VEHICLE_INFO(TrackVehicleInfoDiagDown60ToFlatLongBase3,{ + { 15, 15, 47, 28, 55, 0 },{ 15, 15, 46, 28, 55, 0 },{ 14, 14, 45, 28, 55, 0 },{ 14, 14, 44, 28, 55, 0 },{ 13, 13, 43, 28, 55, 0 }, + { 13, 13, 42, 28, 55, 0 },{ 12, 12, 41, 28, 55, 0 },{ 12, 12, 40, 28, 55, 0 },{ 11, 11, 39, 28, 55, 0 },{ 11, 11, 38, 28, 55, 0 }, + { 10, 10, 37, 28, 55, 0 },{ 9, 9, 36, 28, 55, 0 },{ 9, 9, 35, 28, 55, 0 },{ 8, 8, 34, 28, 55, 0 },{ 8, 8, 33, 28, 55, 0 }, + { 7, 7, 32, 28, 55, 0 },{ 7, 7, 31, 28, 55, 0 },{ 6, 6, 30, 28, 55, 0 },{ 6, 6, 29, 28, 55, 0 },{ 5, 5, 28, 28, 7, 0 }, + { 4, 4, 27, 28, 7, 0 },{ 4, 4, 26, 28, 7, 0 },{ 3, 3, 25, 28, 7, 0 },{ 3, 3, 24, 28, 7, 0 },{ 2, 2, 23, 28, 7, 0 }, + { 1, 1, 22, 28, 7, 0 },{ 1, 1, 21, 28, 7, 0 },{ 0, 0, 20, 28, 7, 0 },{ -1, -1, 19, 28, 7, 0 },{ -1, -1, 18, 28, 7, 0 }, + { -2, -2, 17, 28, 7, 0 },{ -2, -2, 16, 28, 7, 0 },{ -3, -3, 15, 28, 7, 0 },{ -4, -4, 14, 28, 7, 0 },{ -4, -4, 13, 28, 7, 0 }, + { -5, -5, 12, 28, 7, 0 },{ -6, -6, 11, 28, 7, 0 },{ -7, -7, 10, 28, 7, 0 },{ -7, -7, 9, 28, 7, 0 },{ -8, -8, 8, 28, 7, 0 }, + { -9, -9, 7, 28, 7, 0 },{ -9, -9, 6, 28, 7, 0 },{ -10, -10, 5, 28, 7, 0 },{ -11, -11, 4, 28, 7, 0 },{ -12, -12, 3, 28, 7, 0 }, + { -12, -12, 2, 28, 7, 0 },{ -13, -13, 1, 28, 7, 0 },{ -14, -14, 0, 28, 7, 0 },{ -15, -15, -1, 28, 7, 0 },{ -16, -16, -2, 28, 7, 0 }, + { -16, -16, -3, 28, 7, 0 },{ -17, -17, -4, 28, 7, 0 },{ -18, -18, -5, 28, 7, 0 },{ -19, -19, -6, 28, 7, 0 },{ -20, -20, -7, 28, 7, 0 }, + { -21, -21, -8, 28, 7, 0 },{ -22, -22, -9, 28, 7, 0 },{ -23, -23, -10, 28, 7, 0 },{ -23, -23, -11, 28, 7, 0 },{ -24, -24, -12, 28, 6, 0 }, + { -25, -25, -13, 28, 6, 0 },{ -26, -26, -14, 28, 6, 0 },{ -27, -27, -15, 28, 6, 0 },{ -28, -28, -16, 28, 6, 0 },{ -29, -29, -17, 28, 6, 0 }, + { -30, -30, -18, 28, 6, 0 },{ -31, -31, -19, 28, 6, 0 },{ -32, -32, -20, 28, 6, 0 },{ -33, -33, -21, 28, 6, 0 },{ -34, -34, -22, 28, 6, 0 }, + { -35, -35, -23, 28, 6, 0 },{ -36, -36, -23, 28, 6, 0 },{ -37, -37, -24, 28, 6, 0 },{ -38, -38, -25, 28, 6, 0 },{ -39, -39, -26, 28, 6, 0 }, + { -40, -40, -26, 28, 6, 0 },{ -41, -41, -27, 28, 6, 0 },{ -42, -42, -28, 28, 6, 0 },{ -43, -43, -28, 28, 6, 0 },{ -44, -44, -29, 28, 6, 0 }, + { -45, -45, -30, 28, 6, 0 },{ -46, -46, -30, 28, 54, 0 },{ -47, -47, -31, 28, 54, 0 },{ -48, -48, -31, 28, 54, 0 },{ -49, -49, -32, 28, 54, 0 }, + { -50, -50, -32, 28, 54, 0 },{ -51, -51, -33, 28, 54, 0 },{ -52, -52, -33, 28, 54, 0 },{ -53, -53, -34, 28, 54, 0 },{ -54, -54, -34, 28, 54, 0 }, + { -55, -55, -35, 28, 54, 0 },{ -56, -56, -35, 28, 54, 0 },{ -57, -57, -36, 28, 54, 0 },{ -58, -58, -36, 28, 54, 0 },{ -59, -59, -36, 28, 53, 0 }, + { -60, -60, -37, 28, 53, 0 },{ -61, -61, -37, 28, 53, 0 },{ -62, -62, -37, 28, 53, 0 },{ -63, -63, -38, 28, 53, 0 },{ -64, -64, -38, 28, 53, 0 }, + { -65, -65, -38, 28, 53, 0 },{ -66, -66, -38, 28, 53, 0 },{ -67, -67, -39, 28, 53, 0 },{ -68, -68, -39, 28, 53, 0 },{ -69, -69, -39, 28, 53, 0 }, + { -70, -70, -39, 28, 53, 0 },{ -71, -71, -39, 28, 53, 0 },{ -72, -72, -40, 28, 53, 0 },{ -73, -73, -40, 28, 0, 0 },{ -74, -74, -40, 28, 0, 0 }, + { -75, -75, -40, 28, 0, 0 },{ -76, -76, -40, 28, 0, 0 },{ -77, -77, -40, 28, 0, 0 },{ -78, -78, -40, 28, 0, 0 },{ -79, -79, -40, 28, 0, 0 }, +}) + +CREATE_VEHICLE_INFO(TrackVehicleInfoLeftEighthDiveLoopUpToOrthogonal0,{ + { 15, 16, 1, 4, 52, 0 },{ 15, 16, 2, 4, 52, 0 },{ 14, 17, 3, 4, 52, 0 },{ 14, 17, 4, 4, 52, 0 },{ 13, 18, 5, 4, 52, 0 }, + { 13, 18, 6, 4, 52, 0 },{ 12, 19, 7, 4, 52, 0 },{ 12, 19, 8, 4, 52, 0 },{ 11, 19, 9, 4, 52, 0 },{ 11, 20, 10, 4, 52, 0 }, + { 10, 20, 11, 4, 52, 0 },{ 10, 21, 12, 4, 52, 0 },{ 9, 21, 13, 4, 52, 0 },{ 9, 22, 14, 4, 52, 0 },{ 8, 22, 15, 4, 52, 0 }, + { 8, 22, 16, 4, 52, 0 },{ 7, 23, 17, 4, 52, 0 },{ 7, 23, 18, 4, 52, 0 },{ 6, 24, 19, 4, 52, 0 },{ 6, 24, 20, 4, 52, 0 }, + { 5, 24, 21, 4, 52, 0 },{ 5, 25, 22, 4, 52, 0 },{ 4, 25, 23, 4, 52, 0 },{ 4, 26, 24, 4, 52, 0 },{ 3, 26, 25, 4, 52, 0 }, + { 3, 26, 26, 4, 4, 1 },{ 2, 27, 27, 4, 4, 1 },{ 2, 27, 28, 4, 4, 1 },{ 1, 27, 29, 4, 4, 1 },{ 1, 28, 30, 4, 4, 1 }, + { 0, 28, 31, 4, 4, 1 },{ 0, 28, 32, 4, 4, 1 },{ -1, 29, 33, 4, 4, 1 },{ -1, 29, 34, 4, 4, 1 },{ -2, 29, 35, 4, 4, 1 }, + { -2, 30, 36, 4, 4, 1 },{ -3, 30, 37, 4, 4, 1 },{ -3, 30, 38, 4, 4, 1 },{ -4, 31, 39, 4, 4, 1 },{ -4, 31, 40, 4, 4, 1 }, + { -5, 31, 41, 2, 52, 2 },{ -5, 32, 42, 2, 52, 2 },{ -6, 32, 43, 2, 52, 2 },{ -6, 32, 44, 2, 52, 2 },{ -7, 33, 45, 2, 52, 2 }, + { -7, 33, 46, 2, 52, 2 },{ -8, 33, 47, 2, 52, 2 },{ -8, 33, 48, 2, 52, 2 },{ -9, 34, 49, 2, 52, 2 },{ -9, 34, 50, 2, 52, 2 }, + { -10, 34, 51, 2, 52, 2 },{ -10, 35, 52, 2, 52, 2 },{ -11, 35, 53, 2, 52, 2 },{ -11, 35, 54, 2, 52, 2 },{ -12, 35, 55, 2, 52, 5 }, + { -12, 36, 56, 2, 52, 5 },{ -13, 36, 57, 2, 52, 5 },{ -13, 36, 58, 2, 52, 5 },{ -14, 36, 59, 2, 52, 5 },{ -14, 37, 60, 2, 52, 5 }, + { -15, 37, 61, 2, 52, 5 },{ -16, 37, 62, 2, 52, 5 },{ -16, 37, 63, 2, 52, 5 },{ -17, 38, 64, 2, 52, 5 },{ -17, 38, 65, 2, 52, 5 }, + { -18, 38, 66, 2, 52, 5 },{ -18, 38, 67, 2, 52, 5 },{ -19, 38, 68, 2, 52, 5 },{ -19, 39, 69, 2, 52, 5 },{ -20, 39, 70, 2, 52, 5 }, + { -21, 39, 71, 2, 52, 5 },{ -21, 39, 72, 2, 52, 5 },{ -22, 39, 73, 2, 52, 6 },{ -22, 40, 74, 2, 52, 6 },{ -23, 40, 75, 2, 52, 6 }, + { -23, 40, 76, 2, 52, 6 },{ -24, 40, 77, 2, 52, 6 },{ -25, 40, 78, 2, 52, 6 },{ -25, 41, 79, 2, 52, 6 },{ -26, 41, 80, 2, 52, 6 }, + { -26, 41, 81, 2, 52, 6 },{ -27, 41, 82, 2, 52, 6 },{ -28, 41, 83, 2, 52, 6 },{ -28, 42, 84, 2, 52, 6 },{ -29, 42, 85, 2, 52, 6 }, + { -30, 42, 86, 2, 52, 6 },{ -30, 42, 87, 2, 52, 6 },{ -31, 42, 88, 2, 52, 6 },{ -31, 42, 89, 2, 52, 6 },{ -32, 43, 90, 2, 52, 6 }, + { -33, 43, 91, 2, 52, 6 },{ -33, 43, 92, 2, 52, 6 },{ -34, 43, 93, 2, 52, 6 },{ -35, 43, 94, 2, 52, 6 },{ -35, 43, 95, 2, 52, 6 }, + { -36, 43, 96, 2, 52, 6 },{ -37, 44, 97, 2, 52, 6 },{ -38, 44, 98, 2, 52, 6 },{ -38, 44, 99, 2, 3, 8 },{ -39, 44, 100, 2, 3, 8 }, + { -40, 44, 101, 2, 3, 8 },{ -41, 44, 102, 2, 3, 8 },{ -41, 44, 103, 2, 3, 8 },{ -42, 45, 104, 2, 3, 8 },{ -43, 45, 105, 2, 3, 8 }, + { -44, 45, 106, 2, 3, 8 },{ -44, 45, 107, 2, 3, 8 },{ -45, 45, 108, 2, 3, 8 },{ -46, 45, 109, 2, 3, 8 },{ -47, 45, 110, 2, 3, 8 }, + { -48, 45, 111, 2, 3, 8 },{ -49, 45, 112, 2, 3, 8 },{ -49, 45, 113, 2, 3, 8 },{ -50, 46, 114, 2, 3, 8 },{ -51, 46, 115, 2, 3, 8 }, + { -52, 46, 116, 2, 3, 8 },{ -53, 46, 117, 2, 3, 8 },{ -54, 46, 118, 2, 3, 8 },{ -55, 46, 119, 2, 3, 8 },{ -56, 46, 120, 0, 2, 9 }, + { -57, 46, 121, 0, 2, 9 },{ -58, 46, 122, 0, 2, 9 },{ -59, 46, 123, 0, 2, 9 },{ -60, 46, 124, 0, 2, 9 },{ -61, 46, 125, 0, 2, 9 }, + { -62, 46, 126, 0, 2, 9 },{ -63, 47, 127, 0, 2, 9 },{ -64, 47, 127, 0, 2, 9 },{ -65, 47, 128, 0, 2, 9 },{ -66, 47, 129, 0, 2, 9 }, + { -67, 47, 129, 0, 2, 9 },{ -68, 47, 130, 0, 2, 9 },{ -69, 47, 131, 0, 2, 9 },{ -70, 47, 131, 0, 2, 9 },{ -71, 47, 132, 16, 14, 0 }, + { -72, 47, 132, 16, 14, 0 },{ -73, 47, 133, 16, 14, 0 },{ -74, 47, 133, 16, 15, 0 },{ -75, 47, 134, 16, 15, 0 },{ -76, 47, 134, 16, 15, 0 }, + { -77, 47, 135, 16, 15, 0 },{ -78, 47, 135, 16, 15, 0 },{ -79, 47, 136, 16, 15, 0 },{ -80, 47, 136, 16, 15, 0 },{ -81, 47, 136, 16, 15, 0 }, + { -82, 47, 137, 16, 15, 0 },{ -83, 47, 137, 16, 15, 0 },{ -84, 47, 137, 16, 15, 0 },{ -85, 47, 137, 16, 15, 0 },{ -86, 47, 138, 16, 15, 0 }, + { -87, 47, 138, 16, 15, 0 },{ -88, 47, 138, 16, 15, 0 },{ -89, 47, 138, 16, 16, 0 },{ -90, 47, 138, 16, 16, 0 },{ -91, 47, 138, 16, 16, 0 }, + { -92, 47, 139, 16, 16, 0 },{ -93, 47, 139, 16, 16, 0 },{ -94, 47, 139, 16, 16, 0 },{ -95, 47, 139, 16, 16, 0 },{ -96, 47, 139, 16, 16, 0 }, +}) + +CREATE_VEHICLE_INFO(TrackVehicleInfoLeftEighthDiveLoopUpToOrthogonal1,{ + { 16, 16, 0, 12, 52, 0 },{ 17, 17, 1, 12, 52, 0 },{ 17, 17, 2, 12, 52, 0 },{ 18, 18, 3, 12, 52, 0 },{ 18, 18, 4, 12, 52, 0 }, + { 19, 19, 5, 12, 52, 0 },{ 19, 19, 6, 12, 52, 0 },{ 20, 20, 7, 12, 52, 0 },{ 20, 20, 8, 12, 52, 0 },{ 20, 21, 9, 12, 52, 0 }, + { 21, 21, 10, 12, 52, 0 },{ 21, 22, 11, 12, 52, 0 },{ 22, 22, 12, 12, 52, 0 },{ 22, 23, 13, 12, 52, 0 },{ 23, 23, 14, 12, 52, 0 }, + { 23, 24, 15, 12, 52, 0 },{ 23, 24, 16, 12, 52, 0 },{ 24, 25, 17, 12, 52, 0 },{ 24, 25, 18, 12, 52, 0 },{ 25, 26, 19, 12, 52, 0 }, + { 25, 26, 20, 12, 52, 0 },{ 25, 27, 21, 12, 52, 0 },{ 26, 27, 22, 12, 52, 0 },{ 26, 28, 23, 12, 52, 0 },{ 27, 28, 24, 12, 52, 0 }, + { 27, 29, 25, 12, 52, 0 },{ 27, 29, 26, 12, 4, 1 },{ 28, 30, 27, 12, 4, 1 },{ 28, 30, 28, 12, 4, 1 },{ 28, 31, 29, 12, 4, 1 }, + { 29, 31, 30, 12, 4, 1 },{ 29, 32, 31, 12, 4, 1 },{ 29, 32, 32, 12, 4, 1 },{ 30, 33, 33, 12, 4, 1 },{ 30, 33, 34, 12, 4, 1 }, + { 30, 34, 35, 12, 4, 1 },{ 31, 34, 36, 12, 4, 1 },{ 31, 35, 37, 12, 4, 1 },{ 31, 35, 38, 12, 4, 1 },{ 32, 36, 39, 12, 4, 1 }, + { 32, 36, 40, 12, 4, 1 },{ 32, 37, 41, 10, 52, 2 },{ 33, 37, 42, 10, 52, 2 },{ 33, 38, 43, 10, 52, 2 },{ 33, 38, 44, 10, 52, 2 }, + { 34, 39, 45, 10, 52, 2 },{ 34, 39, 46, 10, 52, 2 },{ 34, 40, 47, 10, 52, 2 },{ 34, 40, 48, 10, 52, 2 },{ 35, 41, 49, 10, 52, 2 }, + { 35, 41, 50, 10, 52, 2 },{ 35, 42, 51, 10, 52, 2 },{ 36, 42, 52, 10, 52, 2 },{ 36, 43, 53, 10, 52, 2 },{ 36, 43, 54, 10, 52, 2 }, + { 36, 44, 55, 10, 52, 5 },{ 37, 44, 56, 10, 52, 5 },{ 37, 45, 57, 10, 52, 5 },{ 37, 45, 58, 10, 52, 5 },{ 37, 46, 59, 10, 52, 5 }, + { 38, 46, 60, 10, 52, 5 },{ 38, 47, 61, 10, 52, 5 },{ 38, 48, 62, 10, 52, 5 },{ 38, 48, 63, 10, 52, 5 },{ 39, 49, 64, 10, 52, 5 }, + { 39, 49, 65, 10, 52, 5 },{ 39, 50, 66, 10, 52, 5 },{ 39, 50, 67, 10, 52, 5 },{ 39, 51, 68, 10, 52, 5 },{ 40, 51, 69, 10, 52, 5 }, + { 40, 52, 70, 10, 52, 5 },{ 40, 53, 71, 10, 52, 5 },{ 40, 53, 72, 10, 52, 5 },{ 40, 54, 73, 10, 52, 6 },{ 41, 54, 74, 10, 52, 6 }, + { 41, 55, 75, 10, 52, 6 },{ 41, 55, 76, 10, 52, 6 },{ 41, 56, 77, 10, 52, 6 },{ 41, 57, 78, 10, 52, 6 },{ 42, 57, 79, 10, 52, 6 }, + { 42, 58, 80, 10, 52, 6 },{ 42, 58, 81, 10, 52, 6 },{ 42, 59, 82, 10, 52, 6 },{ 42, 60, 83, 10, 52, 6 },{ 43, 60, 84, 10, 52, 6 }, + { 43, 61, 85, 10, 52, 6 },{ 43, 62, 86, 10, 52, 6 },{ 43, 62, 87, 10, 52, 6 },{ 43, 63, 88, 10, 52, 6 },{ 43, 63, 89, 10, 52, 6 }, + { 44, 64, 90, 10, 52, 6 },{ 44, 65, 91, 10, 52, 6 },{ 44, 65, 92, 10, 52, 6 },{ 44, 66, 93, 10, 52, 6 },{ 44, 67, 94, 10, 52, 6 }, + { 44, 67, 95, 10, 52, 6 },{ 44, 68, 96, 10, 52, 6 },{ 45, 69, 97, 10, 52, 6 },{ 45, 70, 98, 10, 52, 6 },{ 45, 70, 99, 10, 3, 8 }, + { 45, 71, 100, 10, 3, 8 },{ 45, 72, 101, 10, 3, 8 },{ 45, 73, 102, 10, 3, 8 },{ 45, 73, 103, 10, 3, 8 },{ 46, 74, 104, 10, 3, 8 }, + { 46, 75, 105, 10, 3, 8 },{ 46, 76, 106, 10, 3, 8 },{ 46, 76, 107, 10, 3, 8 },{ 46, 77, 108, 10, 3, 8 },{ 46, 78, 109, 10, 3, 8 }, + { 46, 79, 110, 10, 3, 8 },{ 46, 80, 111, 10, 3, 8 },{ 46, 81, 112, 10, 3, 8 },{ 46, 81, 113, 10, 3, 8 },{ 47, 82, 114, 10, 3, 8 }, + { 47, 83, 115, 10, 3, 8 },{ 47, 84, 116, 10, 3, 8 },{ 47, 85, 117, 10, 3, 8 },{ 47, 86, 118, 10, 3, 8 },{ 47, 87, 119, 10, 3, 8 }, + { 47, 88, 120, 8, 2, 9 },{ 47, 89, 121, 8, 2, 9 },{ 47, 90, 122, 8, 2, 9 },{ 47, 91, 123, 8, 2, 9 },{ 47, 92, 124, 8, 2, 9 }, + { 47, 93, 125, 8, 2, 9 },{ 47, 94, 126, 8, 2, 9 },{ 48, 95, 127, 8, 2, 9 },{ 48, 96, 127, 8, 2, 9 },{ 48, 97, 128, 8, 2, 9 }, + { 48, 98, 129, 8, 2, 9 },{ 48, 99, 129, 8, 2, 9 },{ 48, 100, 130, 8, 2, 9 },{ 48, 101, 131, 8, 2, 9 },{ 48, 102, 131, 8, 2, 9 }, + { 48, 103, 132, 24, 14, 0 },{ 48, 104, 132, 24, 14, 0 },{ 48, 105, 133, 24, 14, 0 },{ 48, 106, 133, 24, 15, 0 },{ 48, 107, 134, 24, 15, 0 }, + { 48, 108, 134, 24, 15, 0 },{ 48, 109, 135, 24, 15, 0 },{ 48, 110, 135, 24, 15, 0 },{ 48, 111, 136, 24, 15, 0 },{ 48, 112, 136, 24, 15, 0 }, + { 48, 113, 136, 24, 15, 0 },{ 48, 114, 137, 24, 15, 0 },{ 48, 115, 137, 24, 15, 0 },{ 48, 116, 137, 24, 15, 0 },{ 48, 117, 137, 24, 15, 0 }, + { 48, 118, 138, 24, 15, 0 },{ 48, 119, 138, 24, 15, 0 },{ 48, 120, 138, 24, 15, 0 },{ 48, 121, 138, 24, 16, 0 },{ 48, 122, 138, 24, 16, 0 }, + { 48, 123, 138, 24, 16, 0 },{ 48, 124, 139, 24, 16, 0 },{ 48, 125, 139, 24, 16, 0 },{ 48, 126, 139, 24, 16, 0 },{ 48, 127, 139, 24, 16, 0 }, + { 48, 128, 139, 24, 16, 0 },}) + +CREATE_VEHICLE_INFO(TrackVehicleInfoLeftEighthDiveLoopUpToOrthogonal2,{ + { 16, 15, 0, 20, 52, 0 },{ 17, 14, 1, 20, 52, 0 },{ 17, 14, 2, 20, 52, 0 },{ 18, 13, 3, 20, 52, 0 },{ 18, 13, 4, 20, 52, 0 }, + { 19, 12, 5, 20, 52, 0 },{ 19, 12, 6, 20, 52, 0 },{ 20, 11, 7, 20, 52, 0 },{ 20, 11, 8, 20, 52, 0 },{ 21, 11, 9, 20, 52, 0 }, + { 21, 10, 10, 20, 52, 0 },{ 22, 10, 11, 20, 52, 0 },{ 22, 9, 12, 20, 52, 0 },{ 23, 9, 13, 20, 52, 0 },{ 23, 8, 14, 20, 52, 0 }, + { 24, 8, 15, 20, 52, 0 },{ 24, 8, 16, 20, 52, 0 },{ 25, 7, 17, 20, 52, 0 },{ 25, 7, 18, 20, 52, 0 },{ 26, 6, 19, 20, 52, 0 }, + { 26, 6, 20, 20, 52, 0 },{ 27, 6, 21, 20, 52, 0 },{ 27, 5, 22, 20, 52, 0 },{ 28, 5, 23, 20, 52, 0 },{ 28, 4, 24, 20, 52, 0 }, + { 29, 4, 25, 20, 52, 0 },{ 29, 4, 26, 20, 4, 1 },{ 30, 3, 27, 20, 4, 1 },{ 30, 3, 28, 20, 4, 1 },{ 31, 3, 29, 20, 4, 1 }, + { 31, 2, 30, 20, 4, 1 },{ 32, 2, 31, 20, 4, 1 },{ 32, 2, 32, 20, 4, 1 },{ 33, 1, 33, 20, 4, 1 },{ 33, 1, 34, 20, 4, 1 }, + { 34, 1, 35, 20, 4, 1 },{ 34, 0, 36, 20, 4, 1 },{ 35, 0, 37, 20, 4, 1 },{ 35, 0, 38, 20, 4, 1 },{ 36, -1, 39, 20, 4, 1 }, + { 36, -1, 40, 20, 4, 1 },{ 37, -1, 41, 18, 52, 2 },{ 37, -2, 42, 18, 52, 2 },{ 38, -2, 43, 18, 52, 2 },{ 38, -2, 44, 18, 52, 2 }, + { 39, -3, 45, 18, 52, 2 },{ 39, -3, 46, 18, 52, 2 },{ 40, -3, 47, 18, 52, 2 },{ 40, -3, 48, 18, 52, 2 },{ 41, -4, 49, 18, 52, 2 }, + { 41, -4, 50, 18, 52, 2 },{ 42, -4, 51, 18, 52, 2 },{ 42, -5, 52, 18, 52, 2 },{ 43, -5, 53, 18, 52, 2 },{ 43, -5, 54, 18, 52, 2 }, + { 44, -5, 55, 18, 52, 5 },{ 44, -6, 56, 18, 52, 5 },{ 45, -6, 57, 18, 52, 5 },{ 45, -6, 58, 18, 52, 5 },{ 46, -6, 59, 18, 52, 5 }, + { 46, -7, 60, 18, 52, 5 },{ 47, -7, 61, 18, 52, 5 },{ 48, -7, 62, 18, 52, 5 },{ 48, -7, 63, 18, 52, 5 },{ 49, -8, 64, 18, 52, 5 }, + { 49, -8, 65, 18, 52, 5 },{ 50, -8, 66, 18, 52, 5 },{ 50, -8, 67, 18, 52, 5 },{ 51, -8, 68, 18, 52, 5 },{ 51, -9, 69, 18, 52, 5 }, + { 52, -9, 70, 18, 52, 5 },{ 53, -9, 71, 18, 52, 5 },{ 53, -9, 72, 18, 52, 5 },{ 54, -9, 73, 18, 52, 6 },{ 54, -10, 74, 18, 52, 6 }, + { 55, -10, 75, 18, 52, 6 },{ 55, -10, 76, 18, 52, 6 },{ 56, -10, 77, 18, 52, 6 },{ 57, -10, 78, 18, 52, 6 },{ 57, -11, 79, 18, 52, 6 }, + { 58, -11, 80, 18, 52, 6 },{ 58, -11, 81, 18, 52, 6 },{ 59, -11, 82, 18, 52, 6 },{ 60, -11, 83, 18, 52, 6 },{ 60, -12, 84, 18, 52, 6 }, + { 61, -12, 85, 18, 52, 6 },{ 62, -12, 86, 18, 52, 6 },{ 62, -12, 87, 18, 52, 6 },{ 63, -12, 88, 18, 52, 6 },{ 63, -12, 89, 18, 52, 6 }, + { 64, -13, 90, 18, 52, 6 },{ 65, -13, 91, 18, 52, 6 },{ 65, -13, 92, 18, 52, 6 },{ 66, -13, 93, 18, 52, 6 },{ 67, -13, 94, 18, 52, 6 }, + { 67, -13, 95, 18, 52, 6 },{ 68, -13, 96, 18, 52, 6 },{ 69, -14, 97, 18, 52, 6 },{ 70, -14, 98, 18, 52, 6 },{ 70, -14, 99, 18, 3, 8 }, + { 71, -14, 100, 18, 3, 8 },{ 72, -14, 101, 18, 3, 8 },{ 73, -14, 102, 18, 3, 8 },{ 73, -14, 103, 18, 3, 8 },{ 74, -15, 104, 18, 3, 8 }, + { 75, -15, 105, 18, 3, 8 },{ 76, -15, 106, 18, 3, 8 },{ 76, -15, 107, 18, 3, 8 },{ 77, -15, 108, 18, 3, 8 },{ 78, -15, 109, 18, 3, 8 }, + { 79, -15, 110, 18, 3, 8 },{ 80, -15, 111, 18, 3, 8 },{ 81, -15, 112, 18, 3, 8 },{ 81, -15, 113, 18, 3, 8 },{ 82, -16, 114, 18, 3, 8 }, + { 83, -16, 115, 18, 3, 8 },{ 84, -16, 116, 18, 3, 8 },{ 85, -16, 117, 18, 3, 8 },{ 86, -16, 118, 18, 3, 8 },{ 87, -16, 119, 18, 3, 8 }, + { 88, -16, 120, 16, 2, 9 },{ 89, -16, 121, 16, 2, 9 },{ 90, -16, 122, 16, 2, 9 },{ 91, -16, 123, 16, 2, 9 },{ 92, -16, 124, 16, 2, 9 }, + { 93, -16, 125, 16, 2, 9 },{ 94, -16, 126, 16, 2, 9 },{ 95, -17, 127, 16, 2, 9 },{ 96, -17, 127, 16, 2, 9 },{ 97, -17, 128, 16, 2, 9 }, + { 98, -17, 129, 16, 2, 9 },{ 99, -17, 129, 16, 2, 9 },{ 100, -17, 130, 16, 2, 9 },{ 101, -17, 131, 16, 2, 9 },{ 102, -17, 131, 16, 2, 9 }, + { 103, -17, 132, 0, 14, 0 },{ 104, -17, 132, 0, 14, 0 },{ 105, -17, 133, 0, 14, 0 },{ 106, -17, 133, 0, 15, 0 },{ 107, -17, 134, 0, 15, 0 }, + { 108, -17, 134, 0, 15, 0 },{ 109, -17, 135, 0, 15, 0 },{ 110, -17, 135, 0, 15, 0 },{ 111, -17, 136, 0, 15, 0 },{ 112, -17, 136, 0, 15, 0 }, + { 113, -17, 136, 0, 15, 0 },{ 114, -17, 137, 0, 15, 0 },{ 115, -17, 137, 0, 15, 0 },{ 116, -17, 137, 0, 15, 0 },{ 117, -17, 137, 0, 15, 0 }, + { 118, -17, 138, 0, 15, 0 },{ 119, -17, 138, 0, 15, 0 },{ 120, -17, 138, 0, 15, 0 },{ 121, -17, 138, 0, 16, 0 },{ 122, -17, 138, 0, 16, 0 }, + { 123, -17, 138, 0, 16, 0 },{ 124, -17, 139, 0, 16, 0 },{ 125, -17, 139, 0, 16, 0 },{ 126, -17, 139, 0, 16, 0 },{ 127, -17, 139, 0, 16, 0 }, + { 128, -17, 139, 0, 16, 0 },}) + +CREATE_VEHICLE_INFO(TrackVehicleInfoLeftEighthDiveLoopUpToOrthogonal3,{ + { 15, 15, 1, 28, 52, 0 },{ 15, 15, 2, 28, 52, 0 },{ 14, 14, 3, 28, 52, 0 },{ 14, 14, 4, 28, 52, 0 },{ 13, 13, 5, 28, 52, 0 }, + { 13, 13, 6, 28, 52, 0 },{ 12, 12, 7, 28, 52, 0 },{ 12, 12, 8, 28, 52, 0 },{ 12, 11, 9, 28, 52, 0 },{ 11, 11, 10, 28, 52, 0 }, + { 11, 10, 11, 28, 52, 0 },{ 10, 10, 12, 28, 52, 0 },{ 10, 9, 13, 28, 52, 0 },{ 9, 9, 14, 28, 52, 0 },{ 9, 8, 15, 28, 52, 0 }, + { 9, 8, 16, 28, 52, 0 },{ 8, 7, 17, 28, 52, 0 },{ 8, 7, 18, 28, 52, 0 },{ 7, 6, 19, 28, 52, 0 },{ 7, 6, 20, 28, 52, 0 }, + { 7, 5, 21, 28, 52, 0 },{ 6, 5, 22, 28, 52, 0 },{ 6, 4, 23, 28, 52, 0 },{ 5, 4, 24, 28, 52, 0 },{ 5, 3, 25, 28, 52, 0 }, + { 5, 3, 26, 28, 4, 1 },{ 4, 2, 27, 28, 4, 1 },{ 4, 2, 28, 28, 4, 1 },{ 4, 1, 29, 28, 4, 1 },{ 3, 1, 30, 28, 4, 1 }, + { 3, 0, 31, 28, 4, 1 },{ 3, 0, 32, 28, 4, 1 },{ 2, -1, 33, 28, 4, 1 },{ 2, -1, 34, 28, 4, 1 },{ 2, -2, 35, 28, 4, 1 }, + { 1, -2, 36, 28, 4, 1 },{ 1, -3, 37, 28, 4, 1 },{ 1, -3, 38, 28, 4, 1 },{ 0, -4, 39, 28, 4, 1 },{ 0, -4, 40, 28, 4, 1 }, + { 0, -5, 41, 26, 52, 2 },{ -1, -5, 42, 26, 52, 2 },{ -1, -6, 43, 26, 52, 2 },{ -1, -6, 44, 26, 52, 2 },{ -2, -7, 45, 26, 52, 2 }, + { -2, -7, 46, 26, 52, 2 },{ -2, -8, 47, 26, 52, 2 },{ -2, -8, 48, 26, 52, 2 },{ -3, -9, 49, 26, 52, 2 },{ -3, -9, 50, 26, 52, 2 }, + { -3, -10, 51, 26, 52, 2 },{ -4, -10, 52, 26, 52, 2 },{ -4, -11, 53, 26, 52, 2 },{ -4, -11, 54, 26, 52, 2 },{ -4, -12, 55, 26, 52, 5 }, + { -5, -12, 56, 26, 52, 5 },{ -5, -13, 57, 26, 52, 5 },{ -5, -13, 58, 26, 52, 5 },{ -5, -14, 59, 26, 52, 5 },{ -6, -14, 60, 26, 52, 5 }, + { -6, -15, 61, 26, 52, 5 },{ -6, -16, 62, 26, 52, 5 },{ -6, -16, 63, 26, 52, 5 },{ -7, -17, 64, 26, 52, 5 },{ -7, -17, 65, 26, 52, 5 }, + { -7, -18, 66, 26, 52, 5 },{ -7, -18, 67, 26, 52, 5 },{ -7, -19, 68, 26, 52, 5 },{ -8, -19, 69, 26, 52, 5 },{ -8, -20, 70, 26, 52, 5 }, + { -8, -21, 71, 26, 52, 5 },{ -8, -21, 72, 26, 52, 5 },{ -8, -22, 73, 26, 52, 6 },{ -9, -22, 74, 26, 52, 6 },{ -9, -23, 75, 26, 52, 6 }, + { -9, -23, 76, 26, 52, 6 },{ -9, -24, 77, 26, 52, 6 },{ -9, -25, 78, 26, 52, 6 },{ -10, -25, 79, 26, 52, 6 },{ -10, -26, 80, 26, 52, 6 }, + { -10, -26, 81, 26, 52, 6 },{ -10, -27, 82, 26, 52, 6 },{ -10, -28, 83, 26, 52, 6 },{ -11, -28, 84, 26, 52, 6 },{ -11, -29, 85, 26, 52, 6 }, + { -11, -30, 86, 26, 52, 6 },{ -11, -30, 87, 26, 52, 6 },{ -11, -31, 88, 26, 52, 6 },{ -11, -31, 89, 26, 52, 6 },{ -12, -32, 90, 26, 52, 6 }, + { -12, -33, 91, 26, 52, 6 },{ -12, -33, 92, 26, 52, 6 },{ -12, -34, 93, 26, 52, 6 },{ -12, -35, 94, 26, 52, 6 },{ -12, -35, 95, 26, 52, 6 }, + { -12, -36, 96, 26, 52, 6 },{ -13, -37, 97, 26, 52, 6 },{ -13, -38, 98, 26, 52, 6 },{ -13, -38, 99, 26, 3, 8 },{ -13, -39, 100, 26, 3, 8 }, + { -13, -40, 101, 26, 3, 8 },{ -13, -41, 102, 26, 3, 8 },{ -13, -41, 103, 26, 3, 8 },{ -14, -42, 104, 26, 3, 8 },{ -14, -43, 105, 26, 3, 8 }, + { -14, -44, 106, 26, 3, 8 },{ -14, -44, 107, 26, 3, 8 },{ -14, -45, 108, 26, 3, 8 },{ -14, -46, 109, 26, 3, 8 },{ -14, -47, 110, 26, 3, 8 }, + { -14, -48, 111, 26, 3, 8 },{ -14, -49, 112, 26, 3, 8 },{ -14, -49, 113, 26, 3, 8 },{ -15, -50, 114, 26, 3, 8 },{ -15, -51, 115, 26, 3, 8 }, + { -15, -52, 116, 26, 3, 8 },{ -15, -53, 117, 26, 3, 8 },{ -15, -54, 118, 26, 3, 8 },{ -15, -55, 119, 26, 3, 8 },{ -15, -56, 120, 24, 2, 9 }, + { -15, -57, 121, 24, 2, 9 },{ -15, -58, 122, 24, 2, 9 },{ -15, -59, 123, 24, 2, 9 },{ -15, -60, 124, 24, 2, 9 },{ -15, -61, 125, 24, 2, 9 }, + { -15, -62, 126, 24, 2, 9 },{ -16, -63, 127, 24, 2, 9 },{ -16, -64, 127, 24, 2, 9 },{ -16, -65, 128, 24, 2, 9 },{ -16, -66, 129, 24, 2, 9 }, + { -16, -67, 129, 24, 2, 9 },{ -16, -68, 130, 24, 2, 9 },{ -16, -69, 131, 24, 2, 9 },{ -16, -70, 131, 24, 2, 9 },{ -16, -71, 132, 8, 14, 0 }, + { -16, -72, 132, 8, 14, 0 },{ -16, -73, 133, 8, 14, 0 },{ -16, -74, 133, 8, 15, 0 },{ -16, -75, 134, 8, 15, 0 },{ -16, -76, 134, 8, 15, 0 }, + { -16, -77, 135, 8, 15, 0 },{ -16, -78, 135, 8, 15, 0 },{ -16, -79, 136, 8, 15, 0 },{ -16, -80, 136, 8, 15, 0 },{ -16, -81, 136, 8, 15, 0 }, + { -16, -82, 137, 8, 15, 0 },{ -16, -83, 137, 8, 15, 0 },{ -16, -84, 137, 8, 15, 0 },{ -16, -85, 137, 8, 15, 0 },{ -16, -86, 138, 8, 15, 0 }, + { -16, -87, 138, 8, 15, 0 },{ -16, -88, 138, 8, 15, 0 },{ -16, -89, 138, 8, 16, 0 },{ -16, -90, 138, 8, 16, 0 },{ -16, -91, 138, 8, 16, 0 }, + { -16, -92, 139, 8, 16, 0 },{ -16, -93, 139, 8, 16, 0 },{ -16, -94, 139, 8, 16, 0 },{ -16, -95, 139, 8, 16, 0 },{ -16, -96, 139, 8, 16, 0 }, +}) + +CREATE_VEHICLE_INFO(TrackVehicleInfoRightEighthDiveLoopUpToOrthogonal0,{ + { 15, 16, 1, 4, 52, 0 },{ 15, 16, 2, 4, 52, 0 },{ 14, 17, 3, 4, 52, 0 },{ 14, 17, 4, 4, 52, 0 },{ 13, 18, 5, 4, 52, 0 }, + { 13, 18, 6, 4, 52, 0 },{ 12, 19, 7, 4, 52, 0 },{ 12, 19, 8, 4, 52, 0 },{ 12, 20, 9, 4, 52, 0 },{ 11, 20, 10, 4, 52, 0 }, + { 11, 21, 11, 4, 52, 0 },{ 10, 21, 12, 4, 52, 0 },{ 10, 22, 13, 4, 52, 0 },{ 9, 22, 14, 4, 52, 0 },{ 9, 23, 15, 4, 52, 0 }, + { 9, 23, 16, 4, 52, 0 },{ 8, 24, 17, 4, 52, 0 },{ 8, 24, 18, 4, 52, 0 },{ 7, 25, 19, 4, 52, 0 },{ 7, 25, 20, 4, 52, 0 }, + { 7, 26, 21, 4, 52, 0 },{ 6, 26, 22, 4, 52, 0 },{ 6, 27, 23, 4, 52, 0 },{ 5, 27, 24, 4, 52, 0 },{ 5, 28, 25, 4, 52, 0 }, + { 5, 28, 26, 4, 4, 3 },{ 4, 29, 27, 4, 4, 3 },{ 4, 29, 28, 4, 4, 3 },{ 4, 30, 29, 4, 4, 3 },{ 3, 30, 30, 4, 4, 3 }, + { 3, 31, 31, 4, 4, 3 },{ 3, 31, 32, 4, 4, 3 },{ 2, 32, 33, 4, 4, 3 },{ 2, 32, 34, 4, 4, 3 },{ 2, 33, 35, 4, 4, 3 }, + { 1, 33, 36, 4, 4, 3 },{ 1, 34, 37, 4, 4, 3 },{ 1, 34, 38, 4, 4, 3 },{ 0, 35, 39, 4, 4, 3 },{ 0, 35, 40, 4, 4, 3 }, + { 0, 36, 41, 6, 52, 4 },{ -1, 36, 42, 6, 52, 4 },{ -1, 37, 43, 6, 52, 4 },{ -1, 37, 44, 6, 52, 4 },{ -2, 38, 45, 6, 52, 4 }, + { -2, 38, 46, 6, 52, 4 },{ -2, 39, 47, 6, 52, 4 },{ -2, 39, 48, 6, 52, 4 },{ -3, 40, 49, 6, 52, 4 },{ -3, 40, 50, 6, 52, 4 }, + { -3, 41, 51, 6, 52, 4 },{ -4, 41, 52, 6, 52, 4 },{ -4, 42, 53, 6, 52, 4 },{ -4, 42, 54, 6, 52, 4 },{ -4, 43, 55, 6, 52, 10 }, + { -5, 43, 56, 6, 52, 10 },{ -5, 44, 57, 6, 52, 10 },{ -5, 44, 58, 6, 52, 10 },{ -5, 45, 59, 6, 52, 10 },{ -6, 45, 60, 6, 52, 10 }, + { -6, 46, 61, 6, 52, 10 },{ -6, 47, 62, 6, 52, 10 },{ -6, 47, 63, 6, 52, 10 },{ -7, 48, 64, 6, 52, 10 },{ -7, 48, 65, 6, 52, 10 }, + { -7, 49, 66, 6, 52, 10 },{ -7, 49, 67, 6, 52, 10 },{ -7, 50, 68, 6, 52, 10 },{ -8, 50, 69, 6, 52, 10 },{ -8, 51, 70, 6, 52, 10 }, + { -8, 52, 71, 6, 52, 10 },{ -8, 52, 72, 6, 52, 10 },{ -8, 53, 73, 6, 52, 11 },{ -9, 53, 74, 6, 52, 11 },{ -9, 54, 75, 6, 52, 11 }, + { -9, 54, 76, 6, 52, 11 },{ -9, 55, 77, 6, 52, 11 },{ -9, 56, 78, 6, 52, 11 },{ -10, 56, 79, 6, 52, 11 },{ -10, 57, 80, 6, 52, 11 }, + { -10, 57, 81, 6, 52, 11 },{ -10, 58, 82, 6, 52, 11 },{ -10, 59, 83, 6, 52, 11 },{ -11, 59, 84, 6, 52, 11 },{ -11, 60, 85, 6, 52, 11 }, + { -11, 61, 86, 6, 52, 11 },{ -11, 61, 87, 6, 52, 11 },{ -11, 62, 88, 6, 52, 11 },{ -11, 62, 89, 6, 52, 11 },{ -12, 63, 90, 6, 52, 11 }, + { -12, 64, 91, 6, 52, 11 },{ -12, 64, 92, 6, 52, 11 },{ -12, 65, 93, 6, 52, 11 },{ -12, 66, 94, 6, 52, 11 },{ -12, 66, 95, 6, 52, 11 }, + { -12, 67, 96, 6, 52, 11 },{ -13, 68, 97, 6, 52, 11 },{ -13, 69, 98, 6, 52, 11 },{ -13, 69, 99, 6, 3, 13 },{ -13, 70, 100, 6, 3, 13 }, + { -13, 71, 101, 6, 3, 13 },{ -13, 72, 102, 6, 3, 13 },{ -13, 72, 103, 6, 3, 13 },{ -14, 73, 104, 6, 3, 13 },{ -14, 74, 105, 6, 3, 13 }, + { -14, 75, 106, 6, 3, 13 },{ -14, 75, 107, 6, 3, 13 },{ -14, 76, 108, 6, 3, 13 },{ -14, 77, 109, 6, 3, 13 },{ -14, 78, 110, 6, 3, 13 }, + { -14, 79, 111, 6, 3, 13 },{ -14, 80, 112, 6, 3, 13 },{ -14, 80, 113, 6, 3, 13 },{ -15, 81, 114, 6, 3, 13 },{ -15, 82, 115, 6, 3, 13 }, + { -15, 83, 116, 6, 3, 13 },{ -15, 84, 117, 6, 3, 13 },{ -15, 85, 118, 6, 3, 13 },{ -15, 86, 119, 6, 3, 13 },{ -15, 87, 120, 8, 2, 14 }, + { -15, 88, 121, 8, 2, 14 },{ -15, 89, 122, 8, 2, 14 },{ -15, 90, 123, 8, 2, 14 },{ -15, 91, 124, 8, 2, 14 },{ -15, 92, 125, 8, 2, 14 }, + { -15, 93, 126, 8, 2, 14 },{ -16, 94, 127, 8, 2, 14 },{ -16, 95, 127, 8, 2, 14 },{ -16, 96, 128, 8, 2, 14 },{ -16, 97, 129, 8, 2, 14 }, + { -16, 98, 129, 8, 2, 14 },{ -16, 99, 130, 8, 2, 14 },{ -16, 100, 131, 8, 2, 14 },{ -16, 101, 131, 8, 2, 14 },{ -16, 102, 132, 24, 14, 0 }, + { -16, 103, 132, 24, 14, 0 },{ -16, 104, 133, 24, 14, 0 },{ -16, 105, 133, 24, 15, 0 },{ -16, 106, 134, 24, 15, 0 },{ -16, 107, 134, 24, 15, 0 }, + { -16, 108, 135, 24, 15, 0 },{ -16, 109, 135, 24, 15, 0 },{ -16, 110, 136, 24, 15, 0 },{ -16, 111, 136, 24, 15, 0 },{ -16, 112, 136, 24, 15, 0 }, + { -16, 113, 137, 24, 15, 0 },{ -16, 114, 137, 24, 15, 0 },{ -16, 115, 137, 24, 15, 0 },{ -16, 116, 137, 24, 15, 0 },{ -16, 117, 138, 24, 15, 0 }, + { -16, 118, 138, 24, 15, 0 },{ -16, 119, 138, 24, 15, 0 },{ -16, 120, 138, 24, 16, 0 },{ -16, 121, 138, 24, 16, 0 },{ -16, 122, 138, 24, 16, 0 }, + { -16, 123, 139, 24, 16, 0 },{ -16, 124, 139, 24, 16, 0 },{ -16, 125, 139, 24, 16, 0 },{ -16, 126, 139, 24, 16, 0 },{ -16, 127, 139, 24, 16, 0 }, +}) + +CREATE_VEHICLE_INFO(TrackVehicleInfoRightEighthDiveLoopUpToOrthogonal1,{ + { 16, 16, 0, 12, 52, 0 },{ 17, 17, 1, 12, 52, 0 },{ 17, 17, 2, 12, 52, 0 },{ 18, 18, 3, 12, 52, 0 },{ 18, 18, 4, 12, 52, 0 }, + { 19, 19, 5, 12, 52, 0 },{ 19, 19, 6, 12, 52, 0 },{ 20, 20, 7, 12, 52, 0 },{ 20, 20, 8, 12, 52, 0 },{ 21, 20, 9, 12, 52, 0 }, + { 21, 21, 10, 12, 52, 0 },{ 22, 21, 11, 12, 52, 0 },{ 22, 22, 12, 12, 52, 0 },{ 23, 22, 13, 12, 52, 0 },{ 23, 23, 14, 12, 52, 0 }, + { 24, 23, 15, 12, 52, 0 },{ 24, 23, 16, 12, 52, 0 },{ 25, 24, 17, 12, 52, 0 },{ 25, 24, 18, 12, 52, 0 },{ 26, 25, 19, 12, 52, 0 }, + { 26, 25, 20, 12, 52, 0 },{ 27, 25, 21, 12, 52, 0 },{ 27, 26, 22, 12, 52, 0 },{ 28, 26, 23, 12, 52, 0 },{ 28, 27, 24, 12, 52, 0 }, + { 29, 27, 25, 12, 52, 0 },{ 29, 27, 26, 12, 4, 3 },{ 30, 28, 27, 12, 4, 3 },{ 30, 28, 28, 12, 4, 3 },{ 31, 28, 29, 12, 4, 3 }, + { 31, 29, 30, 12, 4, 3 },{ 32, 29, 31, 12, 4, 3 },{ 32, 29, 32, 12, 4, 3 },{ 33, 30, 33, 12, 4, 3 },{ 33, 30, 34, 12, 4, 3 }, + { 34, 30, 35, 12, 4, 3 },{ 34, 31, 36, 12, 4, 3 },{ 35, 31, 37, 12, 4, 3 },{ 35, 31, 38, 12, 4, 3 },{ 36, 32, 39, 12, 4, 3 }, + { 36, 32, 40, 12, 4, 3 },{ 37, 32, 41, 14, 52, 4 },{ 37, 33, 42, 14, 52, 4 },{ 38, 33, 43, 14, 52, 4 },{ 38, 33, 44, 14, 52, 4 }, + { 39, 34, 45, 14, 52, 4 },{ 39, 34, 46, 14, 52, 4 },{ 40, 34, 47, 14, 52, 4 },{ 40, 34, 48, 14, 52, 4 },{ 41, 35, 49, 14, 52, 4 }, + { 41, 35, 50, 14, 52, 4 },{ 42, 35, 51, 14, 52, 4 },{ 42, 36, 52, 14, 52, 4 },{ 43, 36, 53, 14, 52, 4 },{ 43, 36, 54, 14, 52, 4 }, + { 44, 36, 55, 14, 52, 10 },{ 44, 37, 56, 14, 52, 10 },{ 45, 37, 57, 14, 52, 10 },{ 45, 37, 58, 14, 52, 10 },{ 46, 37, 59, 14, 52, 10 }, + { 46, 38, 60, 14, 52, 10 },{ 47, 38, 61, 14, 52, 10 },{ 48, 38, 62, 14, 52, 10 },{ 48, 38, 63, 14, 52, 10 },{ 49, 39, 64, 14, 52, 10 }, + { 49, 39, 65, 14, 52, 10 },{ 50, 39, 66, 14, 52, 10 },{ 50, 39, 67, 14, 52, 10 },{ 51, 39, 68, 14, 52, 10 },{ 51, 40, 69, 14, 52, 10 }, + { 52, 40, 70, 14, 52, 10 },{ 53, 40, 71, 14, 52, 10 },{ 53, 40, 72, 14, 52, 10 },{ 54, 40, 73, 14, 52, 11 },{ 54, 41, 74, 14, 52, 11 }, + { 55, 41, 75, 14, 52, 11 },{ 55, 41, 76, 14, 52, 11 },{ 56, 41, 77, 14, 52, 11 },{ 57, 41, 78, 14, 52, 11 },{ 57, 42, 79, 14, 52, 11 }, + { 58, 42, 80, 14, 52, 11 },{ 58, 42, 81, 14, 52, 11 },{ 59, 42, 82, 14, 52, 11 },{ 60, 42, 83, 14, 52, 11 },{ 60, 43, 84, 14, 52, 11 }, + { 61, 43, 85, 14, 52, 11 },{ 62, 43, 86, 14, 52, 11 },{ 62, 43, 87, 14, 52, 11 },{ 63, 43, 88, 14, 52, 11 },{ 63, 43, 89, 14, 52, 11 }, + { 64, 44, 90, 14, 52, 11 },{ 65, 44, 91, 14, 52, 11 },{ 65, 44, 92, 14, 52, 11 },{ 66, 44, 93, 14, 52, 11 },{ 67, 44, 94, 14, 52, 11 }, + { 67, 44, 95, 14, 52, 11 },{ 68, 44, 96, 14, 52, 11 },{ 69, 45, 97, 14, 52, 11 },{ 70, 45, 98, 14, 52, 11 },{ 70, 45, 99, 14, 3, 13 }, + { 71, 45, 100, 14, 3, 13 },{ 72, 45, 101, 14, 3, 13 },{ 73, 45, 102, 14, 3, 13 },{ 73, 45, 103, 14, 3, 13 },{ 74, 46, 104, 14, 3, 13 }, + { 75, 46, 105, 14, 3, 13 },{ 76, 46, 106, 14, 3, 13 },{ 76, 46, 107, 14, 3, 13 },{ 77, 46, 108, 14, 3, 13 },{ 78, 46, 109, 14, 3, 13 }, + { 79, 46, 110, 14, 3, 13 },{ 80, 46, 111, 14, 3, 13 },{ 81, 46, 112, 14, 3, 13 },{ 81, 46, 113, 14, 3, 13 },{ 82, 47, 114, 14, 3, 13 }, + { 83, 47, 115, 14, 3, 13 },{ 84, 47, 116, 14, 3, 13 },{ 85, 47, 117, 14, 3, 13 },{ 86, 47, 118, 14, 3, 13 },{ 87, 47, 119, 14, 3, 13 }, + { 88, 47, 120, 16, 2, 14 },{ 89, 47, 121, 16, 2, 14 },{ 90, 47, 122, 16, 2, 14 },{ 91, 47, 123, 16, 2, 14 },{ 92, 47, 124, 16, 2, 14 }, + { 93, 47, 125, 16, 2, 14 },{ 94, 47, 126, 16, 2, 14 },{ 95, 48, 127, 16, 2, 14 },{ 96, 48, 127, 16, 2, 14 },{ 97, 48, 128, 16, 2, 14 }, + { 98, 48, 129, 16, 2, 14 },{ 99, 48, 129, 16, 2, 14 },{ 100, 48, 130, 16, 2, 14 },{ 101, 48, 131, 16, 2, 14 },{ 102, 48, 131, 16, 2, 14 }, + { 103, 48, 132, 0, 14, 0 },{ 104, 48, 132, 0, 14, 0 },{ 105, 48, 133, 0, 14, 0 },{ 106, 48, 133, 0, 15, 0 },{ 107, 48, 134, 0, 15, 0 }, + { 108, 48, 134, 0, 15, 0 },{ 109, 48, 135, 0, 15, 0 },{ 110, 48, 135, 0, 15, 0 },{ 111, 48, 136, 0, 15, 0 },{ 112, 48, 136, 0, 15, 0 }, + { 113, 48, 136, 0, 15, 0 },{ 114, 48, 137, 0, 15, 0 },{ 115, 48, 137, 0, 15, 0 },{ 116, 48, 137, 0, 15, 0 },{ 117, 48, 137, 0, 15, 0 }, + { 118, 48, 138, 0, 15, 0 },{ 119, 48, 138, 0, 15, 0 },{ 120, 48, 138, 0, 15, 0 },{ 121, 48, 138, 0, 16, 0 },{ 122, 48, 138, 0, 16, 0 }, + { 123, 48, 138, 0, 16, 0 },{ 124, 48, 139, 0, 16, 0 },{ 125, 48, 139, 0, 16, 0 },{ 126, 48, 139, 0, 16, 0 },{ 127, 48, 139, 0, 16, 0 }, + { 128, 48, 139, 0, 16, 0 },}) + +CREATE_VEHICLE_INFO(TrackVehicleInfoRightEighthDiveLoopUpToOrthogonal2,{ + { 16, 15, 0, 20, 52, 0 },{ 17, 14, 1, 20, 52, 0 },{ 17, 14, 2, 20, 52, 0 },{ 18, 13, 3, 20, 52, 0 },{ 18, 13, 4, 20, 52, 0 }, + { 19, 12, 5, 20, 52, 0 },{ 19, 12, 6, 20, 52, 0 },{ 20, 11, 7, 20, 52, 0 },{ 20, 11, 8, 20, 52, 0 },{ 20, 10, 9, 20, 52, 0 }, + { 21, 10, 10, 20, 52, 0 },{ 21, 9, 11, 20, 52, 0 },{ 22, 9, 12, 20, 52, 0 },{ 22, 8, 13, 20, 52, 0 },{ 23, 8, 14, 20, 52, 0 }, + { 23, 7, 15, 20, 52, 0 },{ 23, 7, 16, 20, 52, 0 },{ 24, 6, 17, 20, 52, 0 },{ 24, 6, 18, 20, 52, 0 },{ 25, 5, 19, 20, 52, 0 }, + { 25, 5, 20, 20, 52, 0 },{ 25, 4, 21, 20, 52, 0 },{ 26, 4, 22, 20, 52, 0 },{ 26, 3, 23, 20, 52, 0 },{ 27, 3, 24, 20, 52, 0 }, + { 27, 2, 25, 20, 52, 0 },{ 27, 2, 26, 20, 4, 3 },{ 28, 1, 27, 20, 4, 3 },{ 28, 1, 28, 20, 4, 3 },{ 28, 0, 29, 20, 4, 3 }, + { 29, 0, 30, 20, 4, 3 },{ 29, -1, 31, 20, 4, 3 },{ 29, -1, 32, 20, 4, 3 },{ 30, -2, 33, 20, 4, 3 },{ 30, -2, 34, 20, 4, 3 }, + { 30, -3, 35, 20, 4, 3 },{ 31, -3, 36, 20, 4, 3 },{ 31, -4, 37, 20, 4, 3 },{ 31, -4, 38, 20, 4, 3 },{ 32, -5, 39, 20, 4, 3 }, + { 32, -5, 40, 20, 4, 3 },{ 32, -6, 41, 22, 52, 4 },{ 33, -6, 42, 22, 52, 4 },{ 33, -7, 43, 22, 52, 4 },{ 33, -7, 44, 22, 52, 4 }, + { 34, -8, 45, 22, 52, 4 },{ 34, -8, 46, 22, 52, 4 },{ 34, -9, 47, 22, 52, 4 },{ 34, -9, 48, 22, 52, 4 },{ 35, -10, 49, 22, 52, 4 }, + { 35, -10, 50, 22, 52, 4 },{ 35, -11, 51, 22, 52, 4 },{ 36, -11, 52, 22, 52, 4 },{ 36, -12, 53, 22, 52, 4 },{ 36, -12, 54, 22, 52, 4 }, + { 36, -13, 55, 22, 52, 10 },{ 37, -13, 56, 22, 52, 10 },{ 37, -14, 57, 22, 52, 10 },{ 37, -14, 58, 22, 52, 10 },{ 37, -15, 59, 22, 52, 10 }, + { 38, -15, 60, 22, 52, 10 },{ 38, -16, 61, 22, 52, 10 },{ 38, -17, 62, 22, 52, 10 },{ 38, -17, 63, 22, 52, 10 },{ 39, -18, 64, 22, 52, 10 }, + { 39, -18, 65, 22, 52, 10 },{ 39, -19, 66, 22, 52, 10 },{ 39, -19, 67, 22, 52, 10 },{ 39, -20, 68, 22, 52, 10 },{ 40, -20, 69, 22, 52, 10 }, + { 40, -21, 70, 22, 52, 10 },{ 40, -22, 71, 22, 52, 10 },{ 40, -22, 72, 22, 52, 10 },{ 40, -23, 73, 22, 52, 11 },{ 41, -23, 74, 22, 52, 11 }, + { 41, -24, 75, 22, 52, 11 },{ 41, -24, 76, 22, 52, 11 },{ 41, -25, 77, 22, 52, 11 },{ 41, -26, 78, 22, 52, 11 },{ 42, -26, 79, 22, 52, 11 }, + { 42, -27, 80, 22, 52, 11 },{ 42, -27, 81, 22, 52, 11 },{ 42, -28, 82, 22, 52, 11 },{ 42, -29, 83, 22, 52, 11 },{ 43, -29, 84, 22, 52, 11 }, + { 43, -30, 85, 22, 52, 11 },{ 43, -31, 86, 22, 52, 11 },{ 43, -31, 87, 22, 52, 11 },{ 43, -32, 88, 22, 52, 11 },{ 43, -32, 89, 22, 52, 11 }, + { 44, -33, 90, 22, 52, 11 },{ 44, -34, 91, 22, 52, 11 },{ 44, -34, 92, 22, 52, 11 },{ 44, -35, 93, 22, 52, 11 },{ 44, -36, 94, 22, 52, 11 }, + { 44, -36, 95, 22, 52, 11 },{ 44, -37, 96, 22, 52, 11 },{ 45, -38, 97, 22, 52, 11 },{ 45, -39, 98, 22, 52, 11 },{ 45, -39, 99, 22, 3, 13 }, + { 45, -40, 100, 22, 3, 13 },{ 45, -41, 101, 22, 3, 13 },{ 45, -42, 102, 22, 3, 13 },{ 45, -42, 103, 22, 3, 13 },{ 46, -43, 104, 22, 3, 13 }, + { 46, -44, 105, 22, 3, 13 },{ 46, -45, 106, 22, 3, 13 },{ 46, -45, 107, 22, 3, 13 },{ 46, -46, 108, 22, 3, 13 },{ 46, -47, 109, 22, 3, 13 }, + { 46, -48, 110, 22, 3, 13 },{ 46, -49, 111, 22, 3, 13 },{ 46, -50, 112, 22, 3, 13 },{ 46, -50, 113, 22, 3, 13 },{ 47, -51, 114, 22, 3, 13 }, + { 47, -52, 115, 22, 3, 13 },{ 47, -53, 116, 22, 3, 13 },{ 47, -54, 117, 22, 3, 13 },{ 47, -55, 118, 22, 3, 13 },{ 47, -56, 119, 22, 3, 13 }, + { 47, -57, 120, 24, 2, 14 },{ 47, -58, 121, 24, 2, 14 },{ 47, -59, 122, 24, 2, 14 },{ 47, -60, 123, 24, 2, 14 },{ 47, -61, 124, 24, 2, 14 }, + { 47, -62, 125, 24, 2, 14 },{ 47, -63, 126, 24, 2, 14 },{ 48, -64, 127, 24, 2, 14 },{ 48, -65, 127, 24, 2, 14 },{ 48, -66, 128, 24, 2, 14 }, + { 48, -67, 129, 24, 2, 14 },{ 48, -68, 129, 24, 2, 14 },{ 48, -69, 130, 24, 2, 14 },{ 48, -70, 131, 24, 2, 14 },{ 48, -71, 131, 24, 2, 14 }, + { 48, -72, 132, 8, 14, 0 },{ 48, -73, 132, 8, 14, 0 },{ 48, -74, 133, 8, 14, 0 },{ 48, -75, 133, 8, 15, 0 },{ 48, -76, 134, 8, 15, 0 }, + { 48, -77, 134, 8, 15, 0 },{ 48, -78, 135, 8, 15, 0 },{ 48, -79, 135, 8, 15, 0 },{ 48, -80, 136, 8, 15, 0 },{ 48, -81, 136, 8, 15, 0 }, + { 48, -82, 136, 8, 15, 0 },{ 48, -83, 137, 8, 15, 0 },{ 48, -84, 137, 8, 15, 0 },{ 48, -85, 137, 8, 15, 0 },{ 48, -86, 137, 8, 15, 0 }, + { 48, -87, 138, 8, 15, 0 },{ 48, -88, 138, 8, 15, 0 },{ 48, -89, 138, 8, 15, 0 },{ 48, -90, 138, 8, 16, 0 },{ 48, -91, 138, 8, 16, 0 }, + { 48, -92, 138, 8, 16, 0 },{ 48, -93, 139, 8, 16, 0 },{ 48, -94, 139, 8, 16, 0 },{ 48, -95, 139, 8, 16, 0 },{ 48, -96, 139, 8, 16, 0 }, + { 48, -97, 139, 8, 16, 0 },}) + +CREATE_VEHICLE_INFO(TrackVehicleInfoRightEighthDiveLoopUpToOrthogonal3,{ + { 15, 15, 1, 28, 52, 0 },{ 15, 15, 2, 28, 52, 0 },{ 14, 14, 3, 28, 52, 0 },{ 14, 14, 4, 28, 52, 0 },{ 13, 13, 5, 28, 52, 0 }, + { 13, 13, 6, 28, 52, 0 },{ 12, 12, 7, 28, 52, 0 },{ 12, 12, 8, 28, 52, 0 },{ 11, 12, 9, 28, 52, 0 },{ 11, 11, 10, 28, 52, 0 }, + { 10, 11, 11, 28, 52, 0 },{ 10, 10, 12, 28, 52, 0 },{ 9, 10, 13, 28, 52, 0 },{ 9, 9, 14, 28, 52, 0 },{ 8, 9, 15, 28, 52, 0 }, + { 8, 9, 16, 28, 52, 0 },{ 7, 8, 17, 28, 52, 0 },{ 7, 8, 18, 28, 52, 0 },{ 6, 7, 19, 28, 52, 0 },{ 6, 7, 20, 28, 52, 0 }, + { 5, 7, 21, 28, 52, 0 },{ 5, 6, 22, 28, 52, 0 },{ 4, 6, 23, 28, 52, 0 },{ 4, 5, 24, 28, 52, 0 },{ 3, 5, 25, 28, 52, 0 }, + { 3, 5, 26, 28, 4, 3 },{ 2, 4, 27, 28, 4, 3 },{ 2, 4, 28, 28, 4, 3 },{ 1, 4, 29, 28, 4, 3 },{ 1, 3, 30, 28, 4, 3 }, + { 0, 3, 31, 28, 4, 3 },{ 0, 3, 32, 28, 4, 3 },{ -1, 2, 33, 28, 4, 3 },{ -1, 2, 34, 28, 4, 3 },{ -2, 2, 35, 28, 4, 3 }, + { -2, 1, 36, 28, 4, 3 },{ -3, 1, 37, 28, 4, 3 },{ -3, 1, 38, 28, 4, 3 },{ -4, 0, 39, 28, 4, 3 },{ -4, 0, 40, 28, 4, 3 }, + { -5, 0, 41, 30, 52, 4 },{ -5, -1, 42, 30, 52, 4 },{ -6, -1, 43, 30, 52, 4 },{ -6, -1, 44, 30, 52, 4 },{ -7, -2, 45, 30, 52, 4 }, + { -7, -2, 46, 30, 52, 4 },{ -8, -2, 47, 30, 52, 4 },{ -8, -2, 48, 30, 52, 4 },{ -9, -3, 49, 30, 52, 4 },{ -9, -3, 50, 30, 52, 4 }, + { -10, -3, 51, 30, 52, 4 },{ -10, -4, 52, 30, 52, 4 },{ -11, -4, 53, 30, 52, 4 },{ -11, -4, 54, 30, 52, 4 },{ -12, -4, 55, 30, 52, 10 }, + { -12, -5, 56, 30, 52, 10 },{ -13, -5, 57, 30, 52, 10 },{ -13, -5, 58, 30, 52, 10 },{ -14, -5, 59, 30, 52, 10 },{ -14, -6, 60, 30, 52, 10 }, + { -15, -6, 61, 30, 52, 10 },{ -16, -6, 62, 30, 52, 10 },{ -16, -6, 63, 30, 52, 10 },{ -17, -7, 64, 30, 52, 10 },{ -17, -7, 65, 30, 52, 10 }, + { -18, -7, 66, 30, 52, 10 },{ -18, -7, 67, 30, 52, 10 },{ -19, -7, 68, 30, 52, 10 },{ -19, -8, 69, 30, 52, 10 },{ -20, -8, 70, 30, 52, 10 }, + { -21, -8, 71, 30, 52, 10 },{ -21, -8, 72, 30, 52, 10 },{ -22, -8, 73, 30, 52, 11 },{ -22, -9, 74, 30, 52, 11 },{ -23, -9, 75, 30, 52, 11 }, + { -23, -9, 76, 30, 52, 11 },{ -24, -9, 77, 30, 52, 11 },{ -25, -9, 78, 30, 52, 11 },{ -25, -10, 79, 30, 52, 11 },{ -26, -10, 80, 30, 52, 11 }, + { -26, -10, 81, 30, 52, 11 },{ -27, -10, 82, 30, 52, 11 },{ -28, -10, 83, 30, 52, 11 },{ -28, -11, 84, 30, 52, 11 },{ -29, -11, 85, 30, 52, 11 }, + { -30, -11, 86, 30, 52, 11 },{ -30, -11, 87, 30, 52, 11 },{ -31, -11, 88, 30, 52, 11 },{ -31, -11, 89, 30, 52, 11 },{ -32, -12, 90, 30, 52, 11 }, + { -33, -12, 91, 30, 52, 11 },{ -33, -12, 92, 30, 52, 11 },{ -34, -12, 93, 30, 52, 11 },{ -35, -12, 94, 30, 52, 11 },{ -35, -12, 95, 30, 52, 11 }, + { -36, -12, 96, 30, 52, 11 },{ -37, -13, 97, 30, 52, 11 },{ -38, -13, 98, 30, 52, 11 },{ -38, -13, 99, 30, 3, 13 },{ -39, -13, 100, 30, 3, 13 }, + { -40, -13, 101, 30, 3, 13 },{ -41, -13, 102, 30, 3, 13 },{ -41, -13, 103, 30, 3, 13 },{ -42, -14, 104, 30, 3, 13 },{ -43, -14, 105, 30, 3, 13 }, + { -44, -14, 106, 30, 3, 13 },{ -44, -14, 107, 30, 3, 13 },{ -45, -14, 108, 30, 3, 13 },{ -46, -14, 109, 30, 3, 13 },{ -47, -14, 110, 30, 3, 13 }, + { -48, -14, 111, 30, 3, 13 },{ -49, -14, 112, 30, 3, 13 },{ -49, -14, 113, 30, 3, 13 },{ -50, -15, 114, 30, 3, 13 },{ -51, -15, 115, 30, 3, 13 }, + { -52, -15, 116, 30, 3, 13 },{ -53, -15, 117, 30, 3, 13 },{ -54, -15, 118, 30, 3, 13 },{ -55, -15, 119, 30, 3, 13 },{ -56, -15, 120, 0, 2, 14 }, + { -57, -15, 121, 0, 2, 14 },{ -58, -15, 122, 0, 2, 14 },{ -59, -15, 123, 0, 2, 14 },{ -60, -15, 124, 0, 2, 14 },{ -61, -15, 125, 0, 2, 14 }, + { -62, -15, 126, 0, 2, 14 },{ -63, -16, 127, 0, 2, 14 },{ -64, -16, 127, 0, 2, 14 },{ -65, -16, 128, 0, 2, 14 },{ -66, -16, 129, 0, 2, 14 }, + { -67, -16, 129, 0, 2, 14 },{ -68, -16, 130, 0, 2, 14 },{ -69, -16, 131, 0, 2, 14 },{ -70, -16, 131, 0, 2, 14 },{ -71, -16, 132, 16, 14, 0 }, + { -72, -16, 132, 16, 14, 0 },{ -73, -16, 133, 16, 14, 0 },{ -74, -16, 133, 16, 15, 0 },{ -75, -16, 134, 16, 15, 0 },{ -76, -16, 134, 16, 15, 0 }, + { -77, -16, 135, 16, 15, 0 },{ -78, -16, 135, 16, 15, 0 },{ -79, -16, 136, 16, 15, 0 },{ -80, -16, 136, 16, 15, 0 },{ -81, -16, 136, 16, 15, 0 }, + { -82, -16, 137, 16, 15, 0 },{ -83, -16, 137, 16, 15, 0 },{ -84, -16, 137, 16, 15, 0 },{ -85, -16, 137, 16, 15, 0 },{ -86, -16, 138, 16, 15, 0 }, + { -87, -16, 138, 16, 15, 0 },{ -88, -16, 138, 16, 15, 0 },{ -89, -16, 138, 16, 16, 0 },{ -90, -16, 138, 16, 16, 0 },{ -91, -16, 138, 16, 16, 0 }, + { -92, -16, 139, 16, 16, 0 },{ -93, -16, 139, 16, 16, 0 },{ -94, -16, 139, 16, 16, 0 },{ -95, -16, 139, 16, 16, 0 },{ -96, -16, 139, 16, 16, 0 }, +}) + +CREATE_VEHICLE_INFO(TrackVehicleInfoLeftEighthDiveLoopDownToOrthogonal0,{ + { 31, 16, 27, 16, 16, 0 },{ 30, 16, 27, 16, 16, 0 },{ 29, 16, 27, 16, 16, 0 },{ 28, 16, 27, 16, 16, 0 },{ 27, 16, 26, 16, 16, 0 }, + { 26, 16, 26, 16, 16, 0 },{ 25, 16, 26, 16, 16, 0 },{ 24, 16, 26, 16, 23, 0 },{ 23, 16, 26, 16, 23, 0 },{ 22, 16, 26, 16, 23, 0 }, + { 21, 16, 25, 16, 23, 0 },{ 20, 16, 25, 16, 23, 0 },{ 19, 16, 25, 16, 23, 0 },{ 18, 16, 25, 16, 23, 0 },{ 17, 16, 24, 16, 23, 0 }, + { 16, 16, 24, 16, 23, 0 },{ 15, 16, 24, 16, 23, 0 },{ 14, 16, 23, 16, 23, 0 },{ 13, 16, 23, 16, 23, 0 },{ 12, 16, 22, 16, 23, 0 }, + { 11, 16, 22, 16, 23, 0 },{ 10, 16, 21, 16, 23, 0 },{ 9, 16, 21, 16, 22, 0 },{ 8, 16, 20, 16, 22, 0 },{ 7, 16, 20, 16, 22, 0 }, + { 6, 16, 19, 0, 6, 9 },{ 5, 16, 19, 0, 6, 9 },{ 4, 16, 18, 0, 6, 9 },{ 3, 16, 17, 0, 6, 9 },{ 2, 16, 17, 0, 6, 9 }, + { 1, 16, 16, 0, 6, 9 },{ 0, 16, 15, 0, 6, 9 },{ -1, 16, 15, 0, 6, 9 },{ -2, 15, 14, 0, 6, 9 },{ -3, 15, 13, 0, 6, 9 }, + { -4, 15, 12, 0, 6, 9 },{ -5, 15, 11, 0, 6, 9 },{ -6, 15, 10, 0, 6, 9 },{ -7, 15, 9, 0, 6, 9 },{ -8, 15, 8, 0, 6, 9 }, + { -9, 15, 7, 30, 7, 8 },{ -10, 15, 6, 30, 7, 8 },{ -11, 15, 5, 30, 7, 8 },{ -12, 15, 4, 30, 7, 8 },{ -13, 15, 3, 30, 7, 8 }, + { -14, 15, 2, 30, 7, 8 },{ -15, 14, 1, 30, 7, 8 },{ -15, 14, 0, 30, 7, 8 },{ -16, 14, -1, 30, 7, 8 },{ -17, 14, -2, 30, 7, 8 }, + { -18, 14, -3, 30, 7, 8 },{ -19, 14, -4, 30, 7, 8 },{ -20, 14, -5, 30, 7, 8 },{ -20, 14, -6, 30, 7, 8 },{ -21, 14, -7, 30, 7, 8 }, + { -22, 14, -8, 30, 7, 8 },{ -23, 13, -9, 30, 7, 8 },{ -23, 13, -10, 30, 7, 8 },{ -24, 13, -11, 30, 7, 8 },{ -25, 13, -12, 30, 7, 8 }, + { -26, 13, -13, 30, 7, 8 },{ -26, 13, -14, 30, 55, 6 },{ -27, 13, -15, 30, 55, 6 },{ -28, 12, -16, 30, 55, 6 },{ -29, 12, -17, 30, 55, 6 }, + { -29, 12, -18, 30, 55, 6 },{ -30, 12, -19, 30, 55, 6 },{ -31, 12, -20, 30, 55, 6 },{ -31, 12, -21, 30, 55, 6 },{ -32, 12, -22, 30, 55, 6 }, + { -33, 11, -23, 30, 55, 6 },{ -33, 11, -24, 30, 55, 6 },{ -34, 11, -25, 30, 55, 6 },{ -34, 11, -26, 30, 55, 6 },{ -35, 11, -27, 30, 55, 6 }, + { -36, 11, -28, 30, 55, 6 },{ -36, 10, -29, 30, 55, 6 },{ -37, 10, -30, 30, 55, 6 },{ -38, 10, -31, 30, 55, 6 },{ -38, 10, -32, 30, 55, 6 }, + { -39, 10, -33, 30, 55, 6 },{ -39, 9, -34, 30, 55, 6 },{ -40, 9, -35, 30, 55, 6 },{ -41, 9, -36, 30, 55, 6 },{ -41, 9, -37, 30, 55, 6 }, + { -42, 9, -38, 30, 55, 6 },{ -42, 8, -39, 30, 55, 6 },{ -43, 8, -40, 30, 55, 5 },{ -43, 8, -41, 30, 55, 5 },{ -44, 8, -42, 30, 55, 5 }, + { -45, 8, -43, 30, 55, 5 },{ -45, 7, -44, 30, 55, 5 },{ -46, 7, -45, 30, 55, 5 },{ -46, 7, -46, 30, 55, 5 },{ -47, 7, -47, 30, 55, 5 }, + { -47, 7, -48, 30, 55, 5 },{ -48, 6, -49, 30, 55, 5 },{ -48, 6, -50, 30, 55, 5 },{ -49, 6, -51, 30, 55, 5 },{ -50, 6, -52, 30, 55, 5 }, + { -50, 5, -53, 30, 55, 5 },{ -51, 5, -54, 30, 55, 5 },{ -51, 5, -55, 30, 55, 5 },{ -52, 5, -56, 30, 55, 5 },{ -52, 4, -57, 30, 55, 5 }, + { -53, 4, -58, 30, 55, 2 },{ -53, 4, -59, 30, 55, 2 },{ -54, 4, -60, 30, 55, 2 },{ -54, 3, -61, 30, 55, 2 },{ -55, 3, -62, 30, 55, 2 }, + { -55, 3, -63, 30, 55, 2 },{ -56, 2, -64, 30, 55, 2 },{ -56, 2, -65, 30, 55, 2 },{ -57, 2, -66, 30, 55, 2 },{ -57, 2, -67, 30, 55, 2 }, + { -58, 1, -68, 30, 55, 2 },{ -58, 1, -69, 30, 55, 2 },{ -59, 1, -70, 30, 55, 2 },{ -59, 0, -71, 30, 55, 2 },{ -60, 0, -72, 28, 8, 1 }, + { -60, 0, -73, 28, 8, 1 },{ -61, -1, -74, 28, 8, 1 },{ -61, -1, -75, 28, 8, 1 },{ -62, -1, -76, 28, 8, 1 },{ -62, -2, -77, 28, 8, 1 }, + { -63, -2, -78, 28, 8, 1 },{ -63, -2, -79, 28, 8, 1 },{ -64, -3, -80, 28, 8, 1 },{ -64, -3, -81, 28, 8, 1 },{ -65, -3, -82, 28, 8, 1 }, + { -65, -4, -83, 28, 8, 1 },{ -66, -4, -84, 28, 8, 1 },{ -66, -4, -85, 28, 8, 1 },{ -67, -5, -86, 28, 8, 1 },{ -67, -5, -87, 28, 55, 0 }, + { -68, -5, -88, 28, 55, 0 },{ -68, -6, -89, 28, 55, 0 },{ -69, -6, -90, 28, 55, 0 },{ -69, -7, -91, 28, 55, 0 },{ -70, -7, -92, 28, 55, 0 }, + { -70, -7, -93, 28, 55, 0 },{ -71, -8, -94, 28, 55, 0 },{ -71, -8, -95, 28, 55, 0 },{ -72, -9, -96, 28, 55, 0 },{ -72, -9, -97, 28, 55, 0 }, + { -73, -9, -98, 28, 55, 0 },{ -73, -10, -99, 28, 55, 0 },{ -74, -10, -100, 28, 55, 0 },{ -74, -11, -101, 28, 55, 0 },{ -75, -11, -102, 28, 55, 0 }, + { -75, -12, -103, 28, 55, 0 },{ -76, -12, -104, 28, 55, 0 },{ -76, -12, -105, 28, 55, 0 },{ -77, -13, -106, 28, 55, 0 },{ -77, -13, -107, 28, 55, 0 }, + { -78, -14, -108, 28, 55, 0 },{ -78, -14, -109, 28, 55, 0 },{ -79, -15, -110, 28, 55, 0 },{ -79, -15, -111, 28, 55, 0 },{ -80, -16, -112, 28, 55, 0 }, +}) + +CREATE_VEHICLE_INFO(TrackVehicleInfoLeftEighthDiveLoopDownToOrthogonal1,{ + { 16, 0, 27, 24, 16, 0 },{ 16, 1, 27, 24, 16, 0 },{ 16, 2, 27, 24, 16, 0 },{ 16, 3, 27, 24, 16, 0 },{ 16, 4, 27, 24, 16, 0 }, + { 16, 5, 26, 24, 16, 0 },{ 16, 6, 26, 24, 16, 0 },{ 16, 7, 26, 24, 16, 0 },{ 16, 8, 26, 24, 23, 0 },{ 16, 9, 26, 24, 23, 0 }, + { 16, 10, 26, 24, 23, 0 },{ 16, 11, 25, 24, 23, 0 },{ 16, 12, 25, 24, 23, 0 },{ 16, 13, 25, 24, 23, 0 },{ 16, 14, 25, 24, 23, 0 }, + { 16, 15, 24, 24, 23, 0 },{ 16, 16, 24, 24, 23, 0 },{ 16, 17, 24, 24, 23, 0 },{ 16, 18, 23, 24, 23, 0 },{ 16, 19, 23, 24, 23, 0 }, + { 16, 20, 22, 24, 23, 0 },{ 16, 21, 22, 24, 23, 0 },{ 16, 22, 21, 24, 23, 0 },{ 16, 23, 21, 24, 22, 0 },{ 16, 24, 20, 24, 22, 0 }, + { 16, 25, 20, 24, 22, 0 },{ 16, 26, 19, 8, 6, 9 },{ 16, 27, 19, 8, 6, 9 },{ 16, 28, 18, 8, 6, 9 },{ 16, 29, 17, 8, 6, 9 }, + { 16, 30, 17, 8, 6, 9 },{ 16, 31, 16, 8, 6, 9 },{ 16, 32, 15, 8, 6, 9 },{ 16, 33, 15, 8, 6, 9 },{ 15, 34, 14, 8, 6, 9 }, + { 15, 35, 13, 8, 6, 9 },{ 15, 36, 12, 8, 6, 9 },{ 15, 37, 11, 8, 6, 9 },{ 15, 38, 10, 8, 6, 9 },{ 15, 39, 9, 8, 6, 9 }, + { 15, 40, 8, 8, 6, 9 },{ 15, 41, 7, 6, 7, 8 },{ 15, 42, 6, 6, 7, 8 },{ 15, 43, 5, 6, 7, 8 },{ 15, 44, 4, 6, 7, 8 }, + { 15, 45, 3, 6, 7, 8 },{ 15, 46, 2, 6, 7, 8 },{ 14, 47, 1, 6, 7, 8 },{ 14, 47, 0, 6, 7, 8 },{ 14, 48, -1, 6, 7, 8 }, + { 14, 49, -2, 6, 7, 8 },{ 14, 50, -3, 6, 7, 8 },{ 14, 51, -4, 6, 7, 8 },{ 14, 52, -5, 6, 7, 8 },{ 14, 52, -6, 6, 7, 8 }, + { 14, 53, -7, 6, 7, 8 },{ 14, 54, -8, 6, 7, 8 },{ 13, 55, -9, 6, 7, 8 },{ 13, 55, -10, 6, 7, 8 },{ 13, 56, -11, 6, 7, 8 }, + { 13, 57, -12, 6, 7, 8 },{ 13, 58, -13, 6, 7, 8 },{ 13, 58, -14, 6, 55, 6 },{ 13, 59, -15, 6, 55, 6 },{ 12, 60, -16, 6, 55, 6 }, + { 12, 61, -17, 6, 55, 6 },{ 12, 61, -18, 6, 55, 6 },{ 12, 62, -19, 6, 55, 6 },{ 12, 63, -20, 6, 55, 6 },{ 12, 63, -21, 6, 55, 6 }, + { 12, 64, -22, 6, 55, 6 },{ 11, 65, -23, 6, 55, 6 },{ 11, 65, -24, 6, 55, 6 },{ 11, 66, -25, 6, 55, 6 },{ 11, 66, -26, 6, 55, 6 }, + { 11, 67, -27, 6, 55, 6 },{ 11, 68, -28, 6, 55, 6 },{ 10, 68, -29, 6, 55, 6 },{ 10, 69, -30, 6, 55, 6 },{ 10, 70, -31, 6, 55, 6 }, + { 10, 70, -32, 6, 55, 6 },{ 10, 71, -33, 6, 55, 6 },{ 9, 71, -34, 6, 55, 6 },{ 9, 72, -35, 6, 55, 6 },{ 9, 73, -36, 6, 55, 6 }, + { 9, 73, -37, 6, 55, 6 },{ 9, 74, -38, 6, 55, 6 },{ 8, 74, -39, 6, 55, 6 },{ 8, 75, -40, 6, 55, 5 },{ 8, 75, -41, 6, 55, 5 }, + { 8, 76, -42, 6, 55, 5 },{ 8, 77, -43, 6, 55, 5 },{ 7, 77, -44, 6, 55, 5 },{ 7, 78, -45, 6, 55, 5 },{ 7, 78, -46, 6, 55, 5 }, + { 7, 79, -47, 6, 55, 5 },{ 7, 79, -48, 6, 55, 5 },{ 6, 80, -49, 6, 55, 5 },{ 6, 80, -50, 6, 55, 5 },{ 6, 81, -51, 6, 55, 5 }, + { 6, 82, -52, 6, 55, 5 },{ 5, 82, -53, 6, 55, 5 },{ 5, 83, -54, 6, 55, 5 },{ 5, 83, -55, 6, 55, 5 },{ 5, 84, -56, 6, 55, 5 }, + { 4, 84, -57, 6, 55, 5 },{ 4, 85, -58, 6, 55, 2 },{ 4, 85, -59, 6, 55, 2 },{ 4, 86, -60, 6, 55, 2 },{ 3, 86, -61, 6, 55, 2 }, + { 3, 87, -62, 6, 55, 2 },{ 3, 87, -63, 6, 55, 2 },{ 2, 88, -64, 6, 55, 2 },{ 2, 88, -65, 6, 55, 2 },{ 2, 89, -66, 6, 55, 2 }, + { 2, 89, -67, 6, 55, 2 },{ 1, 90, -68, 6, 55, 2 },{ 1, 90, -69, 6, 55, 2 },{ 1, 91, -70, 6, 55, 2 },{ 0, 91, -71, 6, 55, 2 }, + { 0, 92, -72, 4, 8, 1 },{ 0, 92, -73, 4, 8, 1 },{ -1, 93, -74, 4, 8, 1 },{ -1, 93, -75, 4, 8, 1 },{ -1, 94, -76, 4, 8, 1 }, + { -2, 94, -77, 4, 8, 1 },{ -2, 95, -78, 4, 8, 1 },{ -2, 95, -79, 4, 8, 1 },{ -3, 96, -80, 4, 8, 1 },{ -3, 96, -81, 4, 8, 1 }, + { -3, 97, -82, 4, 8, 1 },{ -4, 97, -83, 4, 8, 1 },{ -4, 98, -84, 4, 8, 1 },{ -4, 98, -85, 4, 8, 1 },{ -5, 99, -86, 4, 8, 1 }, + { -5, 99, -87, 4, 55, 0 },{ -5, 100, -88, 4, 55, 0 },{ -6, 100, -89, 4, 55, 0 },{ -6, 101, -90, 4, 55, 0 },{ -7, 101, -91, 4, 55, 0 }, + { -7, 102, -92, 4, 55, 0 },{ -7, 102, -93, 4, 55, 0 },{ -8, 103, -94, 4, 55, 0 },{ -8, 103, -95, 4, 55, 0 },{ -9, 104, -96, 4, 55, 0 }, + { -9, 104, -97, 4, 55, 0 },{ -9, 105, -98, 4, 55, 0 },{ -10, 105, -99, 4, 55, 0 },{ -10, 106, -100, 4, 55, 0 },{ -11, 106, -101, 4, 55, 0 }, + { -11, 107, -102, 4, 55, 0 },{ -12, 107, -103, 4, 55, 0 },{ -12, 108, -104, 4, 55, 0 },{ -12, 108, -105, 4, 55, 0 },{ -13, 109, -106, 4, 55, 0 }, + { -13, 109, -107, 4, 55, 0 },{ -14, 110, -108, 4, 55, 0 },{ -14, 110, -109, 4, 55, 0 },{ -15, 111, -110, 4, 55, 0 },{ -15, 111, -111, 4, 55, 0 }, + { -16, 112, -112, 4, 55, 0 },}) + +CREATE_VEHICLE_INFO(TrackVehicleInfoLeftEighthDiveLoopDownToOrthogonal2,{ + { 0, 16, 27, 0, 16, 0 },{ 1, 16, 27, 0, 16, 0 },{ 2, 16, 27, 0, 16, 0 },{ 3, 16, 27, 0, 16, 0 },{ 4, 16, 27, 0, 16, 0 }, + { 5, 16, 26, 0, 16, 0 },{ 6, 16, 26, 0, 16, 0 },{ 7, 16, 26, 0, 16, 0 },{ 8, 16, 26, 0, 23, 0 },{ 9, 16, 26, 0, 23, 0 }, + { 10, 16, 26, 0, 23, 0 },{ 11, 16, 25, 0, 23, 0 },{ 12, 16, 25, 0, 23, 0 },{ 13, 16, 25, 0, 23, 0 },{ 14, 16, 25, 0, 23, 0 }, + { 15, 16, 24, 0, 23, 0 },{ 16, 16, 24, 0, 23, 0 },{ 17, 16, 24, 0, 23, 0 },{ 18, 16, 23, 0, 23, 0 },{ 19, 16, 23, 0, 23, 0 }, + { 20, 16, 22, 0, 23, 0 },{ 21, 16, 22, 0, 23, 0 },{ 22, 16, 21, 0, 23, 0 },{ 23, 16, 21, 0, 22, 0 },{ 24, 16, 20, 0, 22, 0 }, + { 25, 16, 20, 0, 22, 0 },{ 26, 16, 19, 16, 6, 9 },{ 27, 16, 19, 16, 6, 9 },{ 28, 16, 18, 16, 6, 9 },{ 29, 16, 17, 16, 6, 9 }, + { 30, 16, 17, 16, 6, 9 },{ 31, 16, 16, 16, 6, 9 },{ 32, 16, 15, 16, 6, 9 },{ 33, 16, 15, 16, 6, 9 },{ 34, 17, 14, 16, 6, 9 }, + { 35, 17, 13, 16, 6, 9 },{ 36, 17, 12, 16, 6, 9 },{ 37, 17, 11, 16, 6, 9 },{ 38, 17, 10, 16, 6, 9 },{ 39, 17, 9, 16, 6, 9 }, + { 40, 17, 8, 16, 6, 9 },{ 41, 17, 7, 14, 7, 8 },{ 42, 17, 6, 14, 7, 8 },{ 43, 17, 5, 14, 7, 8 },{ 44, 17, 4, 14, 7, 8 }, + { 45, 17, 3, 14, 7, 8 },{ 46, 17, 2, 14, 7, 8 },{ 47, 18, 1, 14, 7, 8 },{ 47, 18, 0, 14, 7, 8 },{ 48, 18, -1, 14, 7, 8 }, + { 49, 18, -2, 14, 7, 8 },{ 50, 18, -3, 14, 7, 8 },{ 51, 18, -4, 14, 7, 8 },{ 52, 18, -5, 14, 7, 8 },{ 52, 18, -6, 14, 7, 8 }, + { 53, 18, -7, 14, 7, 8 },{ 54, 18, -8, 14, 7, 8 },{ 55, 19, -9, 14, 7, 8 },{ 55, 19, -10, 14, 7, 8 },{ 56, 19, -11, 14, 7, 8 }, + { 57, 19, -12, 14, 7, 8 },{ 58, 19, -13, 14, 7, 8 },{ 58, 19, -14, 14, 55, 6 },{ 59, 19, -15, 14, 55, 6 },{ 60, 20, -16, 14, 55, 6 }, + { 61, 20, -17, 14, 55, 6 },{ 61, 20, -18, 14, 55, 6 },{ 62, 20, -19, 14, 55, 6 },{ 63, 20, -20, 14, 55, 6 },{ 63, 20, -21, 14, 55, 6 }, + { 64, 20, -22, 14, 55, 6 },{ 65, 21, -23, 14, 55, 6 },{ 65, 21, -24, 14, 55, 6 },{ 66, 21, -25, 14, 55, 6 },{ 66, 21, -26, 14, 55, 6 }, + { 67, 21, -27, 14, 55, 6 },{ 68, 21, -28, 14, 55, 6 },{ 68, 22, -29, 14, 55, 6 },{ 69, 22, -30, 14, 55, 6 },{ 70, 22, -31, 14, 55, 6 }, + { 70, 22, -32, 14, 55, 6 },{ 71, 22, -33, 14, 55, 6 },{ 71, 23, -34, 14, 55, 6 },{ 72, 23, -35, 14, 55, 6 },{ 73, 23, -36, 14, 55, 6 }, + { 73, 23, -37, 14, 55, 6 },{ 74, 23, -38, 14, 55, 6 },{ 74, 24, -39, 14, 55, 6 },{ 75, 24, -40, 14, 55, 5 },{ 75, 24, -41, 14, 55, 5 }, + { 76, 24, -42, 14, 55, 5 },{ 77, 24, -43, 14, 55, 5 },{ 77, 25, -44, 14, 55, 5 },{ 78, 25, -45, 14, 55, 5 },{ 78, 25, -46, 14, 55, 5 }, + { 79, 25, -47, 14, 55, 5 },{ 79, 25, -48, 14, 55, 5 },{ 80, 26, -49, 14, 55, 5 },{ 80, 26, -50, 14, 55, 5 },{ 81, 26, -51, 14, 55, 5 }, + { 82, 26, -52, 14, 55, 5 },{ 82, 27, -53, 14, 55, 5 },{ 83, 27, -54, 14, 55, 5 },{ 83, 27, -55, 14, 55, 5 },{ 84, 27, -56, 14, 55, 5 }, + { 84, 28, -57, 14, 55, 5 },{ 85, 28, -58, 14, 55, 2 },{ 85, 28, -59, 14, 55, 2 },{ 86, 28, -60, 14, 55, 2 },{ 86, 29, -61, 14, 55, 2 }, + { 87, 29, -62, 14, 55, 2 },{ 87, 29, -63, 14, 55, 2 },{ 88, 30, -64, 14, 55, 2 },{ 88, 30, -65, 14, 55, 2 },{ 89, 30, -66, 14, 55, 2 }, + { 89, 30, -67, 14, 55, 2 },{ 90, 31, -68, 14, 55, 2 },{ 90, 31, -69, 14, 55, 2 },{ 91, 31, -70, 14, 55, 2 },{ 91, 32, -71, 14, 55, 2 }, + { 92, 32, -72, 12, 8, 1 },{ 92, 32, -73, 12, 8, 1 },{ 93, 33, -74, 12, 8, 1 },{ 93, 33, -75, 12, 8, 1 },{ 94, 33, -76, 12, 8, 1 }, + { 94, 34, -77, 12, 8, 1 },{ 95, 34, -78, 12, 8, 1 },{ 95, 34, -79, 12, 8, 1 },{ 96, 35, -80, 12, 8, 1 },{ 96, 35, -81, 12, 8, 1 }, + { 97, 35, -82, 12, 8, 1 },{ 97, 36, -83, 12, 8, 1 },{ 98, 36, -84, 12, 8, 1 },{ 98, 36, -85, 12, 8, 1 },{ 99, 37, -86, 12, 8, 1 }, + { 99, 37, -87, 12, 55, 0 },{ 100, 37, -88, 12, 55, 0 },{ 100, 38, -89, 12, 55, 0 },{ 101, 38, -90, 12, 55, 0 },{ 101, 39, -91, 12, 55, 0 }, + { 102, 39, -92, 12, 55, 0 },{ 102, 39, -93, 12, 55, 0 },{ 103, 40, -94, 12, 55, 0 },{ 103, 40, -95, 12, 55, 0 },{ 104, 41, -96, 12, 55, 0 }, + { 104, 41, -97, 12, 55, 0 },{ 105, 41, -98, 12, 55, 0 },{ 105, 42, -99, 12, 55, 0 },{ 106, 42, -100, 12, 55, 0 },{ 106, 43, -101, 12, 55, 0 }, + { 107, 43, -102, 12, 55, 0 },{ 107, 44, -103, 12, 55, 0 },{ 108, 44, -104, 12, 55, 0 },{ 108, 44, -105, 12, 55, 0 },{ 109, 45, -106, 12, 55, 0 }, + { 109, 45, -107, 12, 55, 0 },{ 110, 46, -108, 12, 55, 0 },{ 110, 46, -109, 12, 55, 0 },{ 111, 47, -110, 12, 55, 0 },{ 111, 47, -111, 12, 55, 0 }, + { 112, 48, -112, 12, 55, 0 },}) + +CREATE_VEHICLE_INFO(TrackVehicleInfoLeftEighthDiveLoopDownToOrthogonal3,{ + { 16, 31, 27, 8, 16, 0 },{ 16, 30, 27, 8, 16, 0 },{ 16, 29, 27, 8, 16, 0 },{ 16, 28, 27, 8, 16, 0 },{ 16, 27, 26, 8, 16, 0 }, + { 16, 26, 26, 8, 16, 0 },{ 16, 25, 26, 8, 16, 0 },{ 16, 24, 26, 8, 23, 0 },{ 16, 23, 26, 8, 23, 0 },{ 16, 22, 26, 8, 23, 0 }, + { 16, 21, 25, 8, 23, 0 },{ 16, 20, 25, 8, 23, 0 },{ 16, 19, 25, 8, 23, 0 },{ 16, 18, 25, 8, 23, 0 },{ 16, 17, 24, 8, 23, 0 }, + { 16, 16, 24, 8, 23, 0 },{ 16, 15, 24, 8, 23, 0 },{ 16, 14, 23, 8, 23, 0 },{ 16, 13, 23, 8, 23, 0 },{ 16, 12, 22, 8, 23, 0 }, + { 16, 11, 22, 8, 23, 0 },{ 16, 10, 21, 8, 23, 0 },{ 16, 9, 21, 8, 22, 0 },{ 16, 8, 20, 8, 22, 0 },{ 16, 7, 20, 8, 22, 0 }, + { 16, 6, 19, 24, 6, 9 },{ 16, 5, 19, 24, 6, 9 },{ 16, 4, 18, 24, 6, 9 },{ 16, 3, 17, 24, 6, 9 },{ 16, 2, 17, 24, 6, 9 }, + { 16, 1, 16, 24, 6, 9 },{ 16, 0, 15, 24, 6, 9 },{ 16, -1, 15, 24, 6, 9 },{ 17, -2, 14, 24, 6, 9 },{ 17, -3, 13, 24, 6, 9 }, + { 17, -4, 12, 24, 6, 9 },{ 17, -5, 11, 24, 6, 9 },{ 17, -6, 10, 24, 6, 9 },{ 17, -7, 9, 24, 6, 9 },{ 17, -8, 8, 24, 6, 9 }, + { 17, -9, 7, 22, 7, 8 },{ 17, -10, 6, 22, 7, 8 },{ 17, -11, 5, 22, 7, 8 },{ 17, -12, 4, 22, 7, 8 },{ 17, -13, 3, 22, 7, 8 }, + { 17, -14, 2, 22, 7, 8 },{ 18, -15, 1, 22, 7, 8 },{ 18, -15, 0, 22, 7, 8 },{ 18, -16, -1, 22, 7, 8 },{ 18, -17, -2, 22, 7, 8 }, + { 18, -18, -3, 22, 7, 8 },{ 18, -19, -4, 22, 7, 8 },{ 18, -20, -5, 22, 7, 8 },{ 18, -20, -6, 22, 7, 8 },{ 18, -21, -7, 22, 7, 8 }, + { 18, -22, -8, 22, 7, 8 },{ 19, -23, -9, 22, 7, 8 },{ 19, -23, -10, 22, 7, 8 },{ 19, -24, -11, 22, 7, 8 },{ 19, -25, -12, 22, 7, 8 }, + { 19, -26, -13, 22, 7, 8 },{ 19, -26, -14, 22, 55, 6 },{ 19, -27, -15, 22, 55, 6 },{ 20, -28, -16, 22, 55, 6 },{ 20, -29, -17, 22, 55, 6 }, + { 20, -29, -18, 22, 55, 6 },{ 20, -30, -19, 22, 55, 6 },{ 20, -31, -20, 22, 55, 6 },{ 20, -31, -21, 22, 55, 6 },{ 20, -32, -22, 22, 55, 6 }, + { 21, -33, -23, 22, 55, 6 },{ 21, -33, -24, 22, 55, 6 },{ 21, -34, -25, 22, 55, 6 },{ 21, -34, -26, 22, 55, 6 },{ 21, -35, -27, 22, 55, 6 }, + { 21, -36, -28, 22, 55, 6 },{ 22, -36, -29, 22, 55, 6 },{ 22, -37, -30, 22, 55, 6 },{ 22, -38, -31, 22, 55, 6 },{ 22, -38, -32, 22, 55, 6 }, + { 22, -39, -33, 22, 55, 6 },{ 23, -39, -34, 22, 55, 6 },{ 23, -40, -35, 22, 55, 6 },{ 23, -41, -36, 22, 55, 6 },{ 23, -41, -37, 22, 55, 6 }, + { 23, -42, -38, 22, 55, 6 },{ 24, -42, -39, 22, 55, 6 },{ 24, -43, -40, 22, 55, 5 },{ 24, -43, -41, 22, 55, 5 },{ 24, -44, -42, 22, 55, 5 }, + { 24, -45, -43, 22, 55, 5 },{ 25, -45, -44, 22, 55, 5 },{ 25, -46, -45, 22, 55, 5 },{ 25, -46, -46, 22, 55, 5 },{ 25, -47, -47, 22, 55, 5 }, + { 25, -47, -48, 22, 55, 5 },{ 26, -48, -49, 22, 55, 5 },{ 26, -48, -50, 22, 55, 5 },{ 26, -49, -51, 22, 55, 5 },{ 26, -50, -52, 22, 55, 5 }, + { 27, -50, -53, 22, 55, 5 },{ 27, -51, -54, 22, 55, 5 },{ 27, -51, -55, 22, 55, 5 },{ 27, -52, -56, 22, 55, 5 },{ 28, -52, -57, 22, 55, 5 }, + { 28, -53, -58, 22, 55, 2 },{ 28, -53, -59, 22, 55, 2 },{ 28, -54, -60, 22, 55, 2 },{ 29, -54, -61, 22, 55, 2 },{ 29, -55, -62, 22, 55, 2 }, + { 29, -55, -63, 22, 55, 2 },{ 30, -56, -64, 22, 55, 2 },{ 30, -56, -65, 22, 55, 2 },{ 30, -57, -66, 22, 55, 2 },{ 30, -57, -67, 22, 55, 2 }, + { 31, -58, -68, 22, 55, 2 },{ 31, -58, -69, 22, 55, 2 },{ 31, -59, -70, 22, 55, 2 },{ 32, -59, -71, 22, 55, 2 },{ 32, -60, -72, 20, 8, 1 }, + { 32, -60, -73, 20, 8, 1 },{ 33, -61, -74, 20, 8, 1 },{ 33, -61, -75, 20, 8, 1 },{ 33, -62, -76, 20, 8, 1 },{ 34, -62, -77, 20, 8, 1 }, + { 34, -63, -78, 20, 8, 1 },{ 34, -63, -79, 20, 8, 1 },{ 35, -64, -80, 20, 8, 1 },{ 35, -64, -81, 20, 8, 1 },{ 35, -65, -82, 20, 8, 1 }, + { 36, -65, -83, 20, 8, 1 },{ 36, -66, -84, 20, 8, 1 },{ 36, -66, -85, 20, 8, 1 },{ 37, -67, -86, 20, 8, 1 },{ 37, -67, -87, 20, 55, 0 }, + { 37, -68, -88, 20, 55, 0 },{ 38, -68, -89, 20, 55, 0 },{ 38, -69, -90, 20, 55, 0 },{ 39, -69, -91, 20, 55, 0 },{ 39, -70, -92, 20, 55, 0 }, + { 39, -70, -93, 20, 55, 0 },{ 40, -71, -94, 20, 55, 0 },{ 40, -71, -95, 20, 55, 0 },{ 41, -72, -96, 20, 55, 0 },{ 41, -72, -97, 20, 55, 0 }, + { 41, -73, -98, 20, 55, 0 },{ 42, -73, -99, 20, 55, 0 },{ 42, -74, -100, 20, 55, 0 },{ 43, -74, -101, 20, 55, 0 },{ 43, -75, -102, 20, 55, 0 }, + { 44, -75, -103, 20, 55, 0 },{ 44, -76, -104, 20, 55, 0 },{ 44, -76, -105, 20, 55, 0 },{ 45, -77, -106, 20, 55, 0 },{ 45, -77, -107, 20, 55, 0 }, + { 46, -78, -108, 20, 55, 0 },{ 46, -78, -109, 20, 55, 0 },{ 47, -79, -110, 20, 55, 0 },{ 47, -79, -111, 20, 55, 0 },{ 48, -80, -112, 20, 55, 0 }, +}) + +CREATE_VEHICLE_INFO(TrackVehicleInfoRightEighthDiveLoopDownToOrthogonal0,{ + { 31, 16, 27, 16, 16, 0 },{ 30, 16, 27, 16, 16, 0 },{ 29, 16, 27, 16, 16, 0 },{ 28, 16, 27, 16, 16, 0 },{ 27, 16, 26, 16, 16, 0 }, + { 26, 16, 26, 16, 16, 0 },{ 25, 16, 26, 16, 16, 0 },{ 24, 16, 26, 16, 23, 0 },{ 23, 16, 26, 16, 23, 0 },{ 22, 16, 26, 16, 23, 0 }, + { 21, 16, 25, 16, 23, 0 },{ 20, 16, 25, 16, 23, 0 },{ 19, 16, 25, 16, 23, 0 },{ 18, 16, 25, 16, 23, 0 },{ 17, 16, 24, 16, 23, 0 }, + { 16, 16, 24, 16, 23, 0 },{ 15, 16, 24, 16, 23, 0 },{ 14, 16, 23, 16, 23, 0 },{ 13, 16, 23, 16, 23, 0 },{ 12, 16, 22, 16, 23, 0 }, + { 11, 16, 22, 16, 23, 0 },{ 10, 16, 21, 16, 23, 0 },{ 9, 16, 21, 16, 22, 0 },{ 8, 16, 20, 16, 22, 0 },{ 7, 16, 20, 16, 22, 0 }, + { 6, 16, 19, 0, 6, 14 },{ 5, 16, 19, 0, 6, 14 },{ 4, 16, 18, 0, 6, 14 },{ 3, 16, 17, 0, 6, 14 },{ 2, 16, 17, 0, 6, 14 }, + { 1, 16, 16, 0, 6, 14 },{ 0, 16, 15, 0, 6, 14 },{ -1, 16, 15, 0, 6, 14 },{ -2, 17, 14, 0, 6, 14 },{ -3, 17, 13, 0, 6, 14 }, + { -4, 17, 12, 0, 6, 14 },{ -5, 17, 11, 0, 6, 14 },{ -6, 17, 10, 0, 6, 14 },{ -7, 17, 9, 0, 6, 14 },{ -8, 17, 8, 0, 6, 14 }, + { -9, 17, 7, 2, 7, 13 },{ -10, 17, 6, 2, 7, 13 },{ -11, 17, 5, 2, 7, 13 },{ -12, 17, 4, 2, 7, 13 },{ -13, 17, 3, 2, 7, 13 }, + { -14, 17, 2, 2, 7, 13 },{ -15, 18, 1, 2, 7, 13 },{ -15, 18, 0, 2, 7, 13 },{ -16, 18, -1, 2, 7, 13 },{ -17, 18, -2, 2, 7, 13 }, + { -18, 18, -3, 2, 7, 13 },{ -19, 18, -4, 2, 7, 13 },{ -20, 18, -5, 2, 7, 13 },{ -20, 18, -6, 2, 7, 13 },{ -21, 18, -7, 2, 7, 13 }, + { -22, 18, -8, 2, 7, 13 },{ -23, 19, -9, 2, 7, 13 },{ -23, 19, -10, 2, 7, 13 },{ -24, 19, -11, 2, 7, 13 },{ -25, 19, -12, 2, 7, 13 }, + { -26, 19, -13, 2, 7, 13 },{ -26, 19, -14, 2, 55, 11 },{ -27, 19, -15, 2, 55, 11 },{ -28, 20, -16, 2, 55, 11 },{ -29, 20, -17, 2, 55, 11 }, + { -29, 20, -18, 2, 55, 11 },{ -30, 20, -19, 2, 55, 11 },{ -31, 20, -20, 2, 55, 11 },{ -31, 20, -21, 2, 55, 11 },{ -32, 20, -22, 2, 55, 11 }, + { -33, 21, -23, 2, 55, 11 },{ -33, 21, -24, 2, 55, 11 },{ -34, 21, -25, 2, 55, 11 },{ -34, 21, -26, 2, 55, 11 },{ -35, 21, -27, 2, 55, 11 }, + { -36, 21, -28, 2, 55, 11 },{ -36, 22, -29, 2, 55, 11 },{ -37, 22, -30, 2, 55, 11 },{ -38, 22, -31, 2, 55, 11 },{ -38, 22, -32, 2, 55, 11 }, + { -39, 22, -33, 2, 55, 11 },{ -39, 23, -34, 2, 55, 11 },{ -40, 23, -35, 2, 55, 11 },{ -41, 23, -36, 2, 55, 11 },{ -41, 23, -37, 2, 55, 11 }, + { -42, 23, -38, 2, 55, 11 },{ -42, 24, -39, 2, 55, 11 },{ -43, 24, -40, 2, 55, 10 },{ -43, 24, -41, 2, 55, 10 },{ -44, 24, -42, 2, 55, 10 }, + { -45, 24, -43, 2, 55, 10 },{ -45, 25, -44, 2, 55, 10 },{ -46, 25, -45, 2, 55, 10 },{ -46, 25, -46, 2, 55, 10 },{ -47, 25, -47, 2, 55, 10 }, + { -47, 25, -48, 2, 55, 10 },{ -48, 26, -49, 2, 55, 10 },{ -48, 26, -50, 2, 55, 10 },{ -49, 26, -51, 2, 55, 10 },{ -50, 26, -52, 2, 55, 10 }, + { -50, 27, -53, 2, 55, 10 },{ -51, 27, -54, 2, 55, 10 },{ -51, 27, -55, 2, 55, 10 },{ -52, 27, -56, 2, 55, 10 },{ -52, 28, -57, 2, 55, 10 }, + { -53, 28, -58, 2, 55, 4 },{ -53, 28, -59, 2, 55, 4 },{ -54, 28, -60, 2, 55, 4 },{ -54, 29, -61, 2, 55, 4 },{ -55, 29, -62, 2, 55, 4 }, + { -55, 29, -63, 2, 55, 4 },{ -56, 30, -64, 2, 55, 4 },{ -56, 30, -65, 2, 55, 4 },{ -57, 30, -66, 2, 55, 4 },{ -57, 30, -67, 2, 55, 4 }, + { -58, 31, -68, 2, 55, 4 },{ -58, 31, -69, 2, 55, 4 },{ -59, 31, -70, 2, 55, 4 },{ -59, 32, -71, 2, 55, 4 },{ -60, 32, -72, 4, 8, 3 }, + { -60, 32, -73, 4, 8, 3 },{ -61, 33, -74, 4, 8, 3 },{ -61, 33, -75, 4, 8, 3 },{ -62, 33, -76, 4, 8, 3 },{ -62, 34, -77, 4, 8, 3 }, + { -63, 34, -78, 4, 8, 3 },{ -63, 34, -79, 4, 8, 3 },{ -64, 35, -80, 4, 8, 3 },{ -64, 35, -81, 4, 8, 3 },{ -65, 35, -82, 4, 8, 3 }, + { -65, 36, -83, 4, 8, 3 },{ -66, 36, -84, 4, 8, 3 },{ -66, 36, -85, 4, 8, 3 },{ -67, 37, -86, 4, 8, 3 },{ -67, 37, -87, 4, 55, 0 }, + { -68, 37, -88, 4, 55, 0 },{ -68, 38, -89, 4, 55, 0 },{ -69, 38, -90, 4, 55, 0 },{ -69, 39, -91, 4, 55, 0 },{ -70, 39, -92, 4, 55, 0 }, + { -70, 39, -93, 4, 55, 0 },{ -71, 40, -94, 4, 55, 0 },{ -71, 40, -95, 4, 55, 0 },{ -72, 41, -96, 4, 55, 0 },{ -72, 41, -97, 4, 55, 0 }, + { -73, 41, -98, 4, 55, 0 },{ -73, 42, -99, 4, 55, 0 },{ -74, 42, -100, 4, 55, 0 },{ -74, 43, -101, 4, 55, 0 },{ -75, 43, -102, 4, 55, 0 }, + { -75, 44, -103, 4, 55, 0 },{ -76, 44, -104, 4, 55, 0 },{ -76, 44, -105, 4, 55, 0 },{ -77, 45, -106, 4, 55, 0 },{ -77, 45, -107, 4, 55, 0 }, + { -78, 46, -108, 4, 55, 0 },{ -78, 46, -109, 4, 55, 0 },{ -79, 47, -110, 4, 55, 0 },{ -79, 47, -111, 4, 55, 0 },{ -80, 48, -112, 4, 55, 0 }, +}) + +CREATE_VEHICLE_INFO(TrackVehicleInfoRightEighthDiveLoopDownToOrthogonal1,{ + { 16, 0, 27, 24, 16, 0 },{ 16, 1, 27, 24, 16, 0 },{ 16, 2, 27, 24, 16, 0 },{ 16, 3, 27, 24, 16, 0 },{ 16, 4, 27, 24, 16, 0 }, + { 16, 5, 26, 24, 16, 0 },{ 16, 6, 26, 24, 16, 0 },{ 16, 7, 26, 24, 16, 0 },{ 16, 8, 26, 24, 23, 0 },{ 16, 9, 26, 24, 23, 0 }, + { 16, 10, 26, 24, 23, 0 },{ 16, 11, 25, 24, 23, 0 },{ 16, 12, 25, 24, 23, 0 },{ 16, 13, 25, 24, 23, 0 },{ 16, 14, 25, 24, 23, 0 }, + { 16, 15, 24, 24, 23, 0 },{ 16, 16, 24, 24, 23, 0 },{ 16, 17, 24, 24, 23, 0 },{ 16, 18, 23, 24, 23, 0 },{ 16, 19, 23, 24, 23, 0 }, + { 16, 20, 22, 24, 23, 0 },{ 16, 21, 22, 24, 23, 0 },{ 16, 22, 21, 24, 23, 0 },{ 16, 23, 21, 24, 22, 0 },{ 16, 24, 20, 24, 22, 0 }, + { 16, 25, 20, 24, 22, 0 },{ 16, 26, 19, 8, 6, 14 },{ 16, 27, 19, 8, 6, 14 },{ 16, 28, 18, 8, 6, 14 },{ 16, 29, 17, 8, 6, 14 }, + { 16, 30, 17, 8, 6, 14 },{ 16, 31, 16, 8, 6, 14 },{ 16, 32, 15, 8, 6, 14 },{ 16, 33, 15, 8, 6, 14 },{ 17, 34, 14, 8, 6, 14 }, + { 17, 35, 13, 8, 6, 14 },{ 17, 36, 12, 8, 6, 14 },{ 17, 37, 11, 8, 6, 14 },{ 17, 38, 10, 8, 6, 14 },{ 17, 39, 9, 8, 6, 14 }, + { 17, 40, 8, 8, 6, 14 },{ 17, 41, 7, 10, 7, 13 },{ 17, 42, 6, 10, 7, 13 },{ 17, 43, 5, 10, 7, 13 },{ 17, 44, 4, 10, 7, 13 }, + { 17, 45, 3, 10, 7, 13 },{ 17, 46, 2, 10, 7, 13 },{ 18, 47, 1, 10, 7, 13 },{ 18, 47, 0, 10, 7, 13 },{ 18, 48, -1, 10, 7, 13 }, + { 18, 49, -2, 10, 7, 13 },{ 18, 50, -3, 10, 7, 13 },{ 18, 51, -4, 10, 7, 13 },{ 18, 52, -5, 10, 7, 13 },{ 18, 52, -6, 10, 7, 13 }, + { 18, 53, -7, 10, 7, 13 },{ 18, 54, -8, 10, 7, 13 },{ 19, 55, -9, 10, 7, 13 },{ 19, 55, -10, 10, 7, 13 },{ 19, 56, -11, 10, 7, 13 }, + { 19, 57, -12, 10, 7, 13 },{ 19, 58, -13, 10, 7, 13 },{ 19, 58, -14, 10, 55, 11 },{ 19, 59, -15, 10, 55, 11 },{ 20, 60, -16, 10, 55, 11 }, + { 20, 61, -17, 10, 55, 11 },{ 20, 61, -18, 10, 55, 11 },{ 20, 62, -19, 10, 55, 11 },{ 20, 63, -20, 10, 55, 11 },{ 20, 63, -21, 10, 55, 11 }, + { 20, 64, -22, 10, 55, 11 },{ 21, 65, -23, 10, 55, 11 },{ 21, 65, -24, 10, 55, 11 },{ 21, 66, -25, 10, 55, 11 },{ 21, 66, -26, 10, 55, 11 }, + { 21, 67, -27, 10, 55, 11 },{ 21, 68, -28, 10, 55, 11 },{ 22, 68, -29, 10, 55, 11 },{ 22, 69, -30, 10, 55, 11 },{ 22, 70, -31, 10, 55, 11 }, + { 22, 70, -32, 10, 55, 11 },{ 22, 71, -33, 10, 55, 11 },{ 23, 71, -34, 10, 55, 11 },{ 23, 72, -35, 10, 55, 11 },{ 23, 73, -36, 10, 55, 11 }, + { 23, 73, -37, 10, 55, 11 },{ 23, 74, -38, 10, 55, 11 },{ 24, 74, -39, 10, 55, 11 },{ 24, 75, -40, 10, 55, 10 },{ 24, 75, -41, 10, 55, 10 }, + { 24, 76, -42, 10, 55, 10 },{ 24, 77, -43, 10, 55, 10 },{ 25, 77, -44, 10, 55, 10 },{ 25, 78, -45, 10, 55, 10 },{ 25, 78, -46, 10, 55, 10 }, + { 25, 79, -47, 10, 55, 10 },{ 25, 79, -48, 10, 55, 10 },{ 26, 80, -49, 10, 55, 10 },{ 26, 80, -50, 10, 55, 10 },{ 26, 81, -51, 10, 55, 10 }, + { 26, 82, -52, 10, 55, 10 },{ 27, 82, -53, 10, 55, 10 },{ 27, 83, -54, 10, 55, 10 },{ 27, 83, -55, 10, 55, 10 },{ 27, 84, -56, 10, 55, 10 }, + { 28, 84, -57, 10, 55, 10 },{ 28, 85, -58, 10, 55, 4 },{ 28, 85, -59, 10, 55, 4 },{ 28, 86, -60, 10, 55, 4 },{ 29, 86, -61, 10, 55, 4 }, + { 29, 87, -62, 10, 55, 4 },{ 29, 87, -63, 10, 55, 4 },{ 30, 88, -64, 10, 55, 4 },{ 30, 88, -65, 10, 55, 4 },{ 30, 89, -66, 10, 55, 4 }, + { 30, 89, -67, 10, 55, 4 },{ 31, 90, -68, 10, 55, 4 },{ 31, 90, -69, 10, 55, 4 },{ 31, 91, -70, 10, 55, 4 },{ 32, 91, -71, 10, 55, 4 }, + { 32, 92, -72, 12, 8, 3 },{ 32, 92, -73, 12, 8, 3 },{ 33, 93, -74, 12, 8, 3 },{ 33, 93, -75, 12, 8, 3 },{ 33, 94, -76, 12, 8, 3 }, + { 34, 94, -77, 12, 8, 3 },{ 34, 95, -78, 12, 8, 3 },{ 34, 95, -79, 12, 8, 3 },{ 35, 96, -80, 12, 8, 3 },{ 35, 96, -81, 12, 8, 3 }, + { 35, 97, -82, 12, 8, 3 },{ 36, 97, -83, 12, 8, 3 },{ 36, 98, -84, 12, 8, 3 },{ 36, 98, -85, 12, 8, 3 },{ 37, 99, -86, 12, 8, 3 }, + { 37, 99, -87, 12, 55, 0 },{ 37, 100, -88, 12, 55, 0 },{ 38, 100, -89, 12, 55, 0 },{ 38, 101, -90, 12, 55, 0 },{ 39, 101, -91, 12, 55, 0 }, + { 39, 102, -92, 12, 55, 0 },{ 39, 102, -93, 12, 55, 0 },{ 40, 103, -94, 12, 55, 0 },{ 40, 103, -95, 12, 55, 0 },{ 41, 104, -96, 12, 55, 0 }, + { 41, 104, -97, 12, 55, 0 },{ 41, 105, -98, 12, 55, 0 },{ 42, 105, -99, 12, 55, 0 },{ 42, 106, -100, 12, 55, 0 },{ 43, 106, -101, 12, 55, 0 }, + { 43, 107, -102, 12, 55, 0 },{ 44, 107, -103, 12, 55, 0 },{ 44, 108, -104, 12, 55, 0 },{ 44, 108, -105, 12, 55, 0 },{ 45, 109, -106, 12, 55, 0 }, + { 45, 109, -107, 12, 55, 0 },{ 46, 110, -108, 12, 55, 0 },{ 46, 110, -109, 12, 55, 0 },{ 47, 111, -110, 12, 55, 0 },{ 47, 111, -111, 12, 55, 0 }, + { 48, 112, -112, 12, 55, 0 },}) + +CREATE_VEHICLE_INFO(TrackVehicleInfoRightEighthDiveLoopDownToOrthogonal2,{ + { 0, 16, 27, 0, 16, 0 },{ 1, 16, 27, 0, 16, 0 },{ 2, 16, 27, 0, 16, 0 },{ 3, 16, 27, 0, 16, 0 },{ 4, 16, 27, 0, 16, 0 }, + { 5, 16, 26, 0, 16, 0 },{ 6, 16, 26, 0, 16, 0 },{ 7, 16, 26, 0, 16, 0 },{ 8, 16, 26, 0, 23, 0 },{ 9, 16, 26, 0, 23, 0 }, + { 10, 16, 26, 0, 23, 0 },{ 11, 16, 25, 0, 23, 0 },{ 12, 16, 25, 0, 23, 0 },{ 13, 16, 25, 0, 23, 0 },{ 14, 16, 25, 0, 23, 0 }, + { 15, 16, 24, 0, 23, 0 },{ 16, 16, 24, 0, 23, 0 },{ 17, 16, 24, 0, 23, 0 },{ 18, 16, 23, 0, 23, 0 },{ 19, 16, 23, 0, 23, 0 }, + { 20, 16, 22, 0, 23, 0 },{ 21, 16, 22, 0, 23, 0 },{ 22, 16, 21, 0, 23, 0 },{ 23, 16, 21, 0, 22, 0 },{ 24, 16, 20, 0, 22, 0 }, + { 25, 16, 20, 0, 22, 0 },{ 26, 16, 19, 16, 6, 14 },{ 27, 16, 19, 16, 6, 14 },{ 28, 16, 18, 16, 6, 14 },{ 29, 16, 17, 16, 6, 14 }, + { 30, 16, 17, 16, 6, 14 },{ 31, 16, 16, 16, 6, 14 },{ 32, 16, 15, 16, 6, 14 },{ 33, 16, 15, 16, 6, 14 },{ 34, 15, 14, 16, 6, 14 }, + { 35, 15, 13, 16, 6, 14 },{ 36, 15, 12, 16, 6, 14 },{ 37, 15, 11, 16, 6, 14 },{ 38, 15, 10, 16, 6, 14 },{ 39, 15, 9, 16, 6, 14 }, + { 40, 15, 8, 16, 6, 14 },{ 41, 15, 7, 18, 7, 13 },{ 42, 15, 6, 18, 7, 13 },{ 43, 15, 5, 18, 7, 13 },{ 44, 15, 4, 18, 7, 13 }, + { 45, 15, 3, 18, 7, 13 },{ 46, 15, 2, 18, 7, 13 },{ 47, 14, 1, 18, 7, 13 },{ 47, 14, 0, 18, 7, 13 },{ 48, 14, -1, 18, 7, 13 }, + { 49, 14, -2, 18, 7, 13 },{ 50, 14, -3, 18, 7, 13 },{ 51, 14, -4, 18, 7, 13 },{ 52, 14, -5, 18, 7, 13 },{ 52, 14, -6, 18, 7, 13 }, + { 53, 14, -7, 18, 7, 13 },{ 54, 14, -8, 18, 7, 13 },{ 55, 13, -9, 18, 7, 13 },{ 55, 13, -10, 18, 7, 13 },{ 56, 13, -11, 18, 7, 13 }, + { 57, 13, -12, 18, 7, 13 },{ 58, 13, -13, 18, 7, 13 },{ 58, 13, -14, 18, 55, 11 },{ 59, 13, -15, 18, 55, 11 },{ 60, 12, -16, 18, 55, 11 }, + { 61, 12, -17, 18, 55, 11 },{ 61, 12, -18, 18, 55, 11 },{ 62, 12, -19, 18, 55, 11 },{ 63, 12, -20, 18, 55, 11 },{ 63, 12, -21, 18, 55, 11 }, + { 64, 12, -22, 18, 55, 11 },{ 65, 11, -23, 18, 55, 11 },{ 65, 11, -24, 18, 55, 11 },{ 66, 11, -25, 18, 55, 11 },{ 66, 11, -26, 18, 55, 11 }, + { 67, 11, -27, 18, 55, 11 },{ 68, 11, -28, 18, 55, 11 },{ 68, 10, -29, 18, 55, 11 },{ 69, 10, -30, 18, 55, 11 },{ 70, 10, -31, 18, 55, 11 }, + { 70, 10, -32, 18, 55, 11 },{ 71, 10, -33, 18, 55, 11 },{ 71, 9, -34, 18, 55, 11 },{ 72, 9, -35, 18, 55, 11 },{ 73, 9, -36, 18, 55, 11 }, + { 73, 9, -37, 18, 55, 11 },{ 74, 9, -38, 18, 55, 11 },{ 74, 8, -39, 18, 55, 11 },{ 75, 8, -40, 18, 55, 10 },{ 75, 8, -41, 18, 55, 10 }, + { 76, 8, -42, 18, 55, 10 },{ 77, 8, -43, 18, 55, 10 },{ 77, 7, -44, 18, 55, 10 },{ 78, 7, -45, 18, 55, 10 },{ 78, 7, -46, 18, 55, 10 }, + { 79, 7, -47, 18, 55, 10 },{ 79, 7, -48, 18, 55, 10 },{ 80, 6, -49, 18, 55, 10 },{ 80, 6, -50, 18, 55, 10 },{ 81, 6, -51, 18, 55, 10 }, + { 82, 6, -52, 18, 55, 10 },{ 82, 5, -53, 18, 55, 10 },{ 83, 5, -54, 18, 55, 10 },{ 83, 5, -55, 18, 55, 10 },{ 84, 5, -56, 18, 55, 10 }, + { 84, 4, -57, 18, 55, 10 },{ 85, 4, -58, 18, 55, 4 },{ 85, 4, -59, 18, 55, 4 },{ 86, 4, -60, 18, 55, 4 },{ 86, 3, -61, 18, 55, 4 }, + { 87, 3, -62, 18, 55, 4 },{ 87, 3, -63, 18, 55, 4 },{ 88, 2, -64, 18, 55, 4 },{ 88, 2, -65, 18, 55, 4 },{ 89, 2, -66, 18, 55, 4 }, + { 89, 2, -67, 18, 55, 4 },{ 90, 1, -68, 18, 55, 4 },{ 90, 1, -69, 18, 55, 4 },{ 91, 1, -70, 18, 55, 4 },{ 91, 0, -71, 18, 55, 4 }, + { 92, 0, -72, 20, 8, 3 },{ 92, 0, -73, 20, 8, 3 },{ 93, -1, -74, 20, 8, 3 },{ 93, -1, -75, 20, 8, 3 },{ 94, -1, -76, 20, 8, 3 }, + { 94, -2, -77, 20, 8, 3 },{ 95, -2, -78, 20, 8, 3 },{ 95, -2, -79, 20, 8, 3 },{ 96, -3, -80, 20, 8, 3 },{ 96, -3, -81, 20, 8, 3 }, + { 97, -3, -82, 20, 8, 3 },{ 97, -4, -83, 20, 8, 3 },{ 98, -4, -84, 20, 8, 3 },{ 98, -4, -85, 20, 8, 3 },{ 99, -5, -86, 20, 8, 3 }, + { 99, -5, -87, 20, 55, 0 },{ 100, -5, -88, 20, 55, 0 },{ 100, -6, -89, 20, 55, 0 },{ 101, -6, -90, 20, 55, 0 },{ 101, -7, -91, 20, 55, 0 }, + { 102, -7, -92, 20, 55, 0 },{ 102, -7, -93, 20, 55, 0 },{ 103, -8, -94, 20, 55, 0 },{ 103, -8, -95, 20, 55, 0 },{ 104, -9, -96, 20, 55, 0 }, + { 104, -9, -97, 20, 55, 0 },{ 105, -9, -98, 20, 55, 0 },{ 105, -10, -99, 20, 55, 0 },{ 106, -10, -100, 20, 55, 0 },{ 106, -11, -101, 20, 55, 0 }, + { 107, -11, -102, 20, 55, 0 },{ 107, -12, -103, 20, 55, 0 },{ 108, -12, -104, 20, 55, 0 },{ 108, -12, -105, 20, 55, 0 },{ 109, -13, -106, 20, 55, 0 }, + { 109, -13, -107, 20, 55, 0 },{ 110, -14, -108, 20, 55, 0 },{ 110, -14, -109, 20, 55, 0 },{ 111, -15, -110, 20, 55, 0 },{ 111, -15, -111, 20, 55, 0 }, + { 112, -16, -112, 20, 55, 0 },}) + +CREATE_VEHICLE_INFO(TrackVehicleInfoRightEighthDiveLoopDownToOrthogonal3,{ + { 16, 31, 27, 8, 16, 0 },{ 16, 30, 27, 8, 16, 0 },{ 16, 29, 27, 8, 16, 0 },{ 16, 28, 27, 8, 16, 0 },{ 16, 27, 26, 8, 16, 0 }, + { 16, 26, 26, 8, 16, 0 },{ 16, 25, 26, 8, 16, 0 },{ 16, 24, 26, 8, 23, 0 },{ 16, 23, 26, 8, 23, 0 },{ 16, 22, 26, 8, 23, 0 }, + { 16, 21, 25, 8, 23, 0 },{ 16, 20, 25, 8, 23, 0 },{ 16, 19, 25, 8, 23, 0 },{ 16, 18, 25, 8, 23, 0 },{ 16, 17, 24, 8, 23, 0 }, + { 16, 16, 24, 8, 23, 0 },{ 16, 15, 24, 8, 23, 0 },{ 16, 14, 23, 8, 23, 0 },{ 16, 13, 23, 8, 23, 0 },{ 16, 12, 22, 8, 23, 0 }, + { 16, 11, 22, 8, 23, 0 },{ 16, 10, 21, 8, 23, 0 },{ 16, 9, 21, 8, 22, 0 },{ 16, 8, 20, 8, 22, 0 },{ 16, 7, 20, 8, 22, 0 }, + { 16, 6, 19, 24, 6, 14 },{ 16, 5, 19, 24, 6, 14 },{ 16, 4, 18, 24, 6, 14 },{ 16, 3, 17, 24, 6, 14 },{ 16, 2, 17, 24, 6, 14 }, + { 16, 1, 16, 24, 6, 14 },{ 16, 0, 15, 24, 6, 14 },{ 16, -1, 15, 24, 6, 14 },{ 15, -2, 14, 24, 6, 14 },{ 15, -3, 13, 24, 6, 14 }, + { 15, -4, 12, 24, 6, 14 },{ 15, -5, 11, 24, 6, 14 },{ 15, -6, 10, 24, 6, 14 },{ 15, -7, 9, 24, 6, 14 },{ 15, -8, 8, 24, 6, 14 }, + { 15, -9, 7, 26, 7, 13 },{ 15, -10, 6, 26, 7, 13 },{ 15, -11, 5, 26, 7, 13 },{ 15, -12, 4, 26, 7, 13 },{ 15, -13, 3, 26, 7, 13 }, + { 15, -14, 2, 26, 7, 13 },{ 14, -15, 1, 26, 7, 13 },{ 14, -15, 0, 26, 7, 13 },{ 14, -16, -1, 26, 7, 13 },{ 14, -17, -2, 26, 7, 13 }, + { 14, -18, -3, 26, 7, 13 },{ 14, -19, -4, 26, 7, 13 },{ 14, -20, -5, 26, 7, 13 },{ 14, -20, -6, 26, 7, 13 },{ 14, -21, -7, 26, 7, 13 }, + { 14, -22, -8, 26, 7, 13 },{ 13, -23, -9, 26, 7, 13 },{ 13, -23, -10, 26, 7, 13 },{ 13, -24, -11, 26, 7, 13 },{ 13, -25, -12, 26, 7, 13 }, + { 13, -26, -13, 26, 7, 13 },{ 13, -26, -14, 26, 55, 11 },{ 13, -27, -15, 26, 55, 11 },{ 12, -28, -16, 26, 55, 11 },{ 12, -29, -17, 26, 55, 11 }, + { 12, -29, -18, 26, 55, 11 },{ 12, -30, -19, 26, 55, 11 },{ 12, -31, -20, 26, 55, 11 },{ 12, -31, -21, 26, 55, 11 },{ 12, -32, -22, 26, 55, 11 }, + { 11, -33, -23, 26, 55, 11 },{ 11, -33, -24, 26, 55, 11 },{ 11, -34, -25, 26, 55, 11 },{ 11, -34, -26, 26, 55, 11 },{ 11, -35, -27, 26, 55, 11 }, + { 11, -36, -28, 26, 55, 11 },{ 10, -36, -29, 26, 55, 11 },{ 10, -37, -30, 26, 55, 11 },{ 10, -38, -31, 26, 55, 11 },{ 10, -38, -32, 26, 55, 11 }, + { 10, -39, -33, 26, 55, 11 },{ 9, -39, -34, 26, 55, 11 },{ 9, -40, -35, 26, 55, 11 },{ 9, -41, -36, 26, 55, 11 },{ 9, -41, -37, 26, 55, 11 }, + { 9, -42, -38, 26, 55, 11 },{ 8, -42, -39, 26, 55, 11 },{ 8, -43, -40, 26, 55, 10 },{ 8, -43, -41, 26, 55, 10 },{ 8, -44, -42, 26, 55, 10 }, + { 8, -45, -43, 26, 55, 10 },{ 7, -45, -44, 26, 55, 10 },{ 7, -46, -45, 26, 55, 10 },{ 7, -46, -46, 26, 55, 10 },{ 7, -47, -47, 26, 55, 10 }, + { 7, -47, -48, 26, 55, 10 },{ 6, -48, -49, 26, 55, 10 },{ 6, -48, -50, 26, 55, 10 },{ 6, -49, -51, 26, 55, 10 },{ 6, -50, -52, 26, 55, 10 }, + { 5, -50, -53, 26, 55, 10 },{ 5, -51, -54, 26, 55, 10 },{ 5, -51, -55, 26, 55, 10 },{ 5, -52, -56, 26, 55, 10 },{ 4, -52, -57, 26, 55, 10 }, + { 4, -53, -58, 26, 55, 4 },{ 4, -53, -59, 26, 55, 4 },{ 4, -54, -60, 26, 55, 4 },{ 3, -54, -61, 26, 55, 4 },{ 3, -55, -62, 26, 55, 4 }, + { 3, -55, -63, 26, 55, 4 },{ 2, -56, -64, 26, 55, 4 },{ 2, -56, -65, 26, 55, 4 },{ 2, -57, -66, 26, 55, 4 },{ 2, -57, -67, 26, 55, 4 }, + { 1, -58, -68, 26, 55, 4 },{ 1, -58, -69, 26, 55, 4 },{ 1, -59, -70, 26, 55, 4 },{ 0, -59, -71, 26, 55, 4 },{ 0, -60, -72, 28, 8, 3 }, + { 0, -60, -73, 28, 8, 3 },{ -1, -61, -74, 28, 8, 3 },{ -1, -61, -75, 28, 8, 3 },{ -1, -62, -76, 28, 8, 3 },{ -2, -62, -77, 28, 8, 3 }, + { -2, -63, -78, 28, 8, 3 },{ -2, -63, -79, 28, 8, 3 },{ -3, -64, -80, 28, 8, 3 },{ -3, -64, -81, 28, 8, 3 },{ -3, -65, -82, 28, 8, 3 }, + { -4, -65, -83, 28, 8, 3 },{ -4, -66, -84, 28, 8, 3 },{ -4, -66, -85, 28, 8, 3 },{ -5, -67, -86, 28, 8, 3 },{ -5, -67, -87, 28, 55, 0 }, + { -5, -68, -88, 28, 55, 0 },{ -6, -68, -89, 28, 55, 0 },{ -6, -69, -90, 28, 55, 0 },{ -7, -69, -91, 28, 55, 0 },{ -7, -70, -92, 28, 55, 0 }, + { -7, -70, -93, 28, 55, 0 },{ -8, -71, -94, 28, 55, 0 },{ -8, -71, -95, 28, 55, 0 },{ -9, -72, -96, 28, 55, 0 },{ -9, -72, -97, 28, 55, 0 }, + { -9, -73, -98, 28, 55, 0 },{ -10, -73, -99, 28, 55, 0 },{ -10, -74, -100, 28, 55, 0 },{ -11, -74, -101, 28, 55, 0 },{ -11, -75, -102, 28, 55, 0 }, + { -12, -75, -103, 28, 55, 0 },{ -12, -76, -104, 28, 55, 0 },{ -12, -76, -105, 28, 55, 0 },{ -13, -77, -106, 28, 55, 0 },{ -13, -77, -107, 28, 55, 0 }, + { -14, -78, -108, 28, 55, 0 },{ -14, -78, -109, 28, 55, 0 },{ -15, -79, -110, 28, 55, 0 },{ -15, -79, -111, 28, 55, 0 },{ -16, -80, -112, 28, 55, 0 }, +}) namespace OpenRCT2::LeftLane @@ -30078,10 +31048,19 @@ static constexpr const VehicleInfoList *TrackVehicleInfoListDefault[] = { &TrackVehicleInfoRightEighthBankToOrthogonalUp250, &TrackVehicleInfoRightEighthBankToOrthogonalUp251, &TrackVehicleInfoRightEighthBankToOrthogonalUp252, &TrackVehicleInfoRightEighthBankToOrthogonalUp253, // TrackElemType::RightEighthBankBankToOrthogonalUp25 &TrackVehicleInfoLeftEighthBankToOrthogonalDown250, &TrackVehicleInfoLeftEighthBankToOrthogonalDown251, &TrackVehicleInfoLeftEighthBankToOrthogonalDown252, &TrackVehicleInfoLeftEighthBankToOrthogonalDown253, // TrackElemType::LeftEighthBankBankToOrthogonalDown25 &TrackVehicleInfoRightEighthBankToOrthogonalDown250, &TrackVehicleInfoRightEighthBankToOrthogonalDown251, &TrackVehicleInfoRightEighthBankToOrthogonalDown252, &TrackVehicleInfoRightEighthBankToOrthogonalDown253, // TrackElemType::RightEighthBankBankToOrthogonalDown25 - &TrackVehicleInfo_9162E6, &TrackVehicleInfo_916408, &TrackVehicleInfo_91652A, &TrackVehicleInfo_91664C, // DiagBrakes - &TrackVehicleInfo_9162E6, &TrackVehicleInfo_916408, &TrackVehicleInfo_91652A, &TrackVehicleInfo_91664C, // DiagBlockBrakes - &TrackVehicleInfo_8C27B2, &TrackVehicleInfo_8C28D4, &TrackVehicleInfo_8C29F6, &TrackVehicleInfo_8C2B18, // SlopedBrakes - &TrackVehicleInfo_9162E6, &TrackVehicleInfo_916408, &TrackVehicleInfo_91652A, &TrackVehicleInfo_91664C, // DiagBooster + &TrackVehicleInfo_9162E6, &TrackVehicleInfo_916408, &TrackVehicleInfo_91652A, &TrackVehicleInfo_91664C, // DiagBrakes + &TrackVehicleInfo_9162E6, &TrackVehicleInfo_916408, &TrackVehicleInfo_91652A, &TrackVehicleInfo_91664C, // DiagBlockBrakes + &TrackVehicleInfo_8C27B2, &TrackVehicleInfo_8C28D4, &TrackVehicleInfo_8C29F6, &TrackVehicleInfo_8C2B18, // SlopedBrakes + &TrackVehicleInfo_9162E6, &TrackVehicleInfo_916408, &TrackVehicleInfo_91652A, &TrackVehicleInfo_91664C, // DiagBooster + &TrackVehicleInfoDiagFlatToUp60LongBase0 , &TrackVehicleInfoDiagFlatToUp60LongBase1 , &TrackVehicleInfoDiagFlatToUp60LongBase2 , &TrackVehicleInfoDiagFlatToUp60LongBase3 , //TrackElemType::DiagFlatToUp60LongBase, + &TrackVehicleInfoDiagUp60ToFlatLongBase0 , &TrackVehicleInfoDiagUp60ToFlatLongBase1 , &TrackVehicleInfoDiagUp60ToFlatLongBase2 , &TrackVehicleInfoDiagUp60ToFlatLongBase3 , //TrackElemType::DiagUp60ToFlatLongBase, + &TrackVehicleInfoDiagFlatToDown60LongBase0, &TrackVehicleInfoDiagFlatToDown60LongBase1, &TrackVehicleInfoDiagFlatToDown60LongBase2, &TrackVehicleInfoDiagFlatToDown60LongBase3, //TrackElemType::DiagFlatToDown60LongBase, + &TrackVehicleInfoDiagDown60ToFlatLongBase0, &TrackVehicleInfoDiagDown60ToFlatLongBase1, &TrackVehicleInfoDiagDown60ToFlatLongBase2, &TrackVehicleInfoDiagDown60ToFlatLongBase3, //TrackElemType::DiagDown60ToFlatLongBase, + + &TrackVehicleInfoLeftEighthDiveLoopUpToOrthogonal0 , &TrackVehicleInfoLeftEighthDiveLoopUpToOrthogonal1 , &TrackVehicleInfoLeftEighthDiveLoopUpToOrthogonal2 , &TrackVehicleInfoLeftEighthDiveLoopUpToOrthogonal3 , //TrackElemType::LeftEighthDiveLoopUpToOrthogonal + &TrackVehicleInfoRightEighthDiveLoopUpToOrthogonal0 , &TrackVehicleInfoRightEighthDiveLoopUpToOrthogonal1 , &TrackVehicleInfoRightEighthDiveLoopUpToOrthogonal2 , &TrackVehicleInfoRightEighthDiveLoopUpToOrthogonal3 , //TrackElemType::RightEighthDiveLoopUpToOrthogonal + &TrackVehicleInfoLeftEighthDiveLoopDownToOrthogonal0 , &TrackVehicleInfoLeftEighthDiveLoopDownToOrthogonal1 , &TrackVehicleInfoLeftEighthDiveLoopDownToOrthogonal2 , &TrackVehicleInfoLeftEighthDiveLoopDownToOrthogonal3 , //TrackElemType::LeftEighthDiveLoopDownToOrthogonal + &TrackVehicleInfoRightEighthDiveLoopDownToOrthogonal0, &TrackVehicleInfoRightEighthDiveLoopDownToOrthogonal1, &TrackVehicleInfoRightEighthDiveLoopDownToOrthogonal2, &TrackVehicleInfoRightEighthDiveLoopDownToOrthogonal3, //TrackElemType::RightEighthDiveLoopDownToOrthogonal }; static_assert(std::size(TrackVehicleInfoListDefault) == VehicleTrackSubpositionSizeDefault); diff --git a/src/openrct2/ride/rtd/coaster/CorkscrewRollerCoaster.h b/src/openrct2/ride/rtd/coaster/CorkscrewRollerCoaster.h index 438a4c8c19..149cd8a6e7 100644 --- a/src/openrct2/ride/rtd/coaster/CorkscrewRollerCoaster.h +++ b/src/openrct2/ride/rtd/coaster/CorkscrewRollerCoaster.h @@ -22,8 +22,8 @@ constexpr RideTypeDescriptor CorkscrewRollerCoasterRTD = .TrackPaintFunctions = TrackDrawerDescriptor({ .trackStyle = TrackStyle::corkscrewRollerCoaster, .supportType = MetalSupportType::Tubes, - .enabledTrackGroups = {TrackGroup::straight, TrackGroup::stationEnd, TrackGroup::liftHill, TrackGroup::flatRollBanking, TrackGroup::verticalLoop, TrackGroup::slope, TrackGroup::slopeSteepUp, TrackGroup::slopeSteepDown, TrackGroup::slopeCurve, TrackGroup::slopeCurveSteep, TrackGroup::sBend, TrackGroup::curveSmall, TrackGroup::curve, TrackGroup::curveLarge, TrackGroup::halfLoop, TrackGroup::corkscrew, TrackGroup::helixDownBankedHalf, TrackGroup::helixUpBankedHalf, TrackGroup::brakes, TrackGroup::onridePhoto, TrackGroup::blockBrakes,TrackGroup::booster, TrackGroup::slopeSteepLong, TrackGroup::diagBrakes, TrackGroup::diagBlockBrakes, TrackGroup::slopeRollBanking, TrackGroup::slopeCurveBanked, TrackGroup::slopeCurveLarge, TrackGroup::corkscrewLarge, TrackGroup::halfLoopMedium, TrackGroup::halfLoopLarge}, - .extraTrackGroups = {TrackGroup::twist, TrackGroup::slopeVertical, TrackGroup::curveVertical, TrackGroup::quarterLoop, TrackGroup::barrelRoll, TrackGroup::zeroGRoll, TrackGroup::zeroGRollLarge}, + .enabledTrackGroups = {TrackGroup::straight, TrackGroup::stationEnd, TrackGroup::liftHill, TrackGroup::flatRollBanking, TrackGroup::verticalLoop, TrackGroup::slope, TrackGroup::slopeSteepUp, TrackGroup::slopeSteepDown, TrackGroup::slopeCurve, TrackGroup::slopeCurveSteep, TrackGroup::sBend, TrackGroup::curveSmall, TrackGroup::curve, TrackGroup::curveLarge, TrackGroup::halfLoop, TrackGroup::corkscrew, TrackGroup::helixDownBankedHalf, TrackGroup::helixUpBankedHalf, TrackGroup::brakes, TrackGroup::onridePhoto, TrackGroup::blockBrakes,TrackGroup::booster, TrackGroup::slopeSteepLong, TrackGroup::diagBrakes, TrackGroup::diagBlockBrakes, TrackGroup::slopeRollBanking, TrackGroup::slopeCurveBanked, TrackGroup::slopeCurveLarge, TrackGroup::corkscrewLarge, TrackGroup::halfLoopMedium, TrackGroup::halfLoopLarge, TrackGroup::diagSlopeSteepLong}, + .extraTrackGroups = {TrackGroup::twist, TrackGroup::slopeVertical, TrackGroup::curveVertical, TrackGroup::quarterLoop, TrackGroup::barrelRoll, TrackGroup::zeroGRoll, TrackGroup::zeroGRollLarge, TrackGroup::diveLoop}, }), .InvertedTrackPaintFunctions = {}, .Flags = kRtdFlagsHasThreeColours | kRtdFlagsCommonCoaster | kRtdFlagsCommonCoasterNonAlt | diff --git a/src/openrct2/ride/rtd/coaster/FlyingRollerCoaster.h b/src/openrct2/ride/rtd/coaster/FlyingRollerCoaster.h index 6db87ee73e..ef8b5737e7 100644 --- a/src/openrct2/ride/rtd/coaster/FlyingRollerCoaster.h +++ b/src/openrct2/ride/rtd/coaster/FlyingRollerCoaster.h @@ -24,7 +24,7 @@ constexpr RideTypeDescriptor FlyingRollerCoasterRTD = .trackStyle = TrackStyle::flyingRollerCoaster, .supportType = MetalSupportType::TubesInverted, .enabledTrackGroups = {TrackGroup::straight, TrackGroup::flatRollBanking, TrackGroup::slope, TrackGroup::slopeSteepUp, TrackGroup::slopeSteepDown, TrackGroup::slopeCurve, TrackGroup::slopeCurveSteep, TrackGroup::sBend, TrackGroup::curveSmall, TrackGroup::curve, TrackGroup::curveLarge, TrackGroup::helixDownBankedHalf, TrackGroup::helixUpBankedHalf, TrackGroup::brakes, TrackGroup::onridePhoto, TrackGroup::blockBrakes, TrackGroup::slopeRollBanking, TrackGroup::inlineTwistUninverted, TrackGroup::flyingHalfLoopUninvertedUp, TrackGroup::quarterLoopUninvertedUp, TrackGroup::flyingLargeHalfLoopUninvertedUp, TrackGroup::slopeVertical, TrackGroup::slopeCurveBanked, TrackGroup::diagBrakes, TrackGroup::diagBlockBrakes, TrackGroup::slopeCurveLarge}, - .extraTrackGroups = {TrackGroup::booster, TrackGroup::slopeSteepLong, TrackGroup::flyingLargeHalfLoopUninvertedDown, TrackGroup::flyingHalfLoopUninvertedDown, TrackGroup::stationEnd, TrackGroup::verticalLoop, TrackGroup::poweredLift}, + .extraTrackGroups = {TrackGroup::booster, TrackGroup::slopeSteepLong, TrackGroup::diagSlopeSteepLong, TrackGroup::flyingLargeHalfLoopUninvertedDown, TrackGroup::flyingHalfLoopUninvertedDown, TrackGroup::stationEnd, TrackGroup::verticalLoop, TrackGroup::poweredLift}, }), .InvertedTrackPaintFunctions = TrackDrawerDescriptor({ .trackStyle = TrackStyle::flyingRollerCoasterInverted, diff --git a/src/openrct2/ride/rtd/coaster/GigaCoaster.h b/src/openrct2/ride/rtd/coaster/GigaCoaster.h index c98a8c4146..19e4c1dc74 100644 --- a/src/openrct2/ride/rtd/coaster/GigaCoaster.h +++ b/src/openrct2/ride/rtd/coaster/GigaCoaster.h @@ -22,8 +22,8 @@ constexpr RideTypeDescriptor GigaCoasterRTD = .TrackPaintFunctions = TrackDrawerDescriptor({ .trackStyle = TrackStyle::latticeTriangle, .supportType = MetalSupportType::Tubes, - .enabledTrackGroups = {TrackGroup::straight, TrackGroup::stationEnd, TrackGroup::liftHill, TrackGroup::flatRollBanking, TrackGroup::slope, TrackGroup::slopeSteepUp, TrackGroup::slopeSteepDown, TrackGroup::slopeCurve, TrackGroup::slopeCurveSteep, TrackGroup::sBend, TrackGroup::curveSmall, TrackGroup::curve, TrackGroup::curveLarge, TrackGroup::helixDownBankedHalf, TrackGroup::helixUpBankedHalf, TrackGroup::brakes, TrackGroup::onridePhoto, TrackGroup::blockBrakes, TrackGroup::slopeRollBanking, TrackGroup::slopeSteepLong, TrackGroup::liftHillCable, TrackGroup::slopeCurveBanked, TrackGroup::slopeCurveLarge, TrackGroup::diagBrakes, TrackGroup::diagBlockBrakes, TrackGroup::slopeVertical, TrackGroup::curveVertical}, - .extraTrackGroups = {TrackGroup::barrelRoll, TrackGroup::quarterLoop, TrackGroup::halfLoop, TrackGroup::halfLoopMedium, TrackGroup::halfLoopLarge, TrackGroup::verticalLoop, TrackGroup::corkscrew, TrackGroup::corkscrewLarge, TrackGroup::zeroGRoll, TrackGroup::zeroGRollLarge, TrackGroup::booster, TrackGroup::diagBooster, TrackGroup::poweredLift}, + .enabledTrackGroups = {TrackGroup::straight, TrackGroup::stationEnd, TrackGroup::liftHill, TrackGroup::flatRollBanking, TrackGroup::slope, TrackGroup::slopeSteepUp, TrackGroup::slopeSteepDown, TrackGroup::slopeCurve, TrackGroup::slopeCurveSteep, TrackGroup::sBend, TrackGroup::curveSmall, TrackGroup::curve, TrackGroup::curveLarge, TrackGroup::helixDownBankedHalf, TrackGroup::helixUpBankedHalf, TrackGroup::brakes, TrackGroup::onridePhoto, TrackGroup::blockBrakes, TrackGroup::slopeRollBanking, TrackGroup::slopeSteepLong, TrackGroup::liftHillCable, TrackGroup::slopeCurveBanked, TrackGroup::slopeCurveLarge, TrackGroup::diagBrakes, TrackGroup::diagBlockBrakes, TrackGroup::slopeVertical, TrackGroup::curveVertical, TrackGroup::diagSlopeSteepLong}, + .extraTrackGroups = {TrackGroup::barrelRoll, TrackGroup::quarterLoop, TrackGroup::halfLoop, TrackGroup::halfLoopMedium, TrackGroup::halfLoopLarge, TrackGroup::verticalLoop, TrackGroup::corkscrew, TrackGroup::corkscrewLarge, TrackGroup::zeroGRoll, TrackGroup::zeroGRollLarge, TrackGroup::booster, TrackGroup::diagBooster, TrackGroup::diveLoop, TrackGroup::poweredLift}, }), .InvertedTrackPaintFunctions = {}, .Flags = kRtdFlagsHasThreeColours | kRtdFlagsCommonCoaster | kRtdFlagsCommonCoasterNonAlt | diff --git a/src/openrct2/ride/rtd/coaster/HyperTwister.h b/src/openrct2/ride/rtd/coaster/HyperTwister.h index 4ba516f512..46f3b6ebb3 100644 --- a/src/openrct2/ride/rtd/coaster/HyperTwister.h +++ b/src/openrct2/ride/rtd/coaster/HyperTwister.h @@ -23,7 +23,7 @@ constexpr RideTypeDescriptor HyperTwisterRTD = .TrackPaintFunctions = TrackDrawerDescriptor({ .trackStyle = TrackStyle::twisterRollerCoaster, .supportType = MetalSupportType::Tubes, - .enabledTrackGroups = { TrackGroup::flat, TrackGroup::straight, TrackGroup::stationEnd, TrackGroup::liftHill, TrackGroup::flatRollBanking, TrackGroup::slope, TrackGroup::slopeSteepUp, TrackGroup::slopeSteepDown, TrackGroup::slopeCurve, TrackGroup::slopeCurveSteep, TrackGroup::sBend, TrackGroup::curveSmall, TrackGroup::curve, TrackGroup::curveLarge, TrackGroup::helixDownBankedHalf, TrackGroup::helixUpBankedHalf, TrackGroup::brakes, TrackGroup::onridePhoto, TrackGroup::slopeCurveBanked, TrackGroup::blockBrakes, TrackGroup::slopeRollBanking, TrackGroup::slopeSteepLong, TrackGroup::slopeVertical, TrackGroup::curveVertical, TrackGroup::diagBrakes, TrackGroup::diagBlockBrakes, TrackGroup::slopeCurveLarge}, + .enabledTrackGroups = { TrackGroup::flat, TrackGroup::straight, TrackGroup::stationEnd, TrackGroup::liftHill, TrackGroup::flatRollBanking, TrackGroup::slope, TrackGroup::slopeSteepUp, TrackGroup::slopeSteepDown, TrackGroup::slopeCurve, TrackGroup::slopeCurveSteep, TrackGroup::sBend, TrackGroup::curveSmall, TrackGroup::curve, TrackGroup::curveLarge, TrackGroup::helixDownBankedHalf, TrackGroup::helixUpBankedHalf, TrackGroup::brakes, TrackGroup::onridePhoto, TrackGroup::slopeCurveBanked, TrackGroup::blockBrakes, TrackGroup::slopeRollBanking, TrackGroup::slopeSteepLong, TrackGroup::slopeVertical, TrackGroup::curveVertical, TrackGroup::diagBrakes, TrackGroup::diagBlockBrakes, TrackGroup::slopeCurveLarge, TrackGroup::diagSlopeSteepLong}, .extraTrackGroups = { TrackGroup::liftHillSteep, TrackGroup::brakeForDrop, TrackGroup::booster, TrackGroup::poweredLift }, }), .InvertedTrackPaintFunctions = {}, diff --git a/src/openrct2/ride/rtd/coaster/Hypercoaster.h b/src/openrct2/ride/rtd/coaster/Hypercoaster.h index 56ba474505..0534e34359 100644 --- a/src/openrct2/ride/rtd/coaster/Hypercoaster.h +++ b/src/openrct2/ride/rtd/coaster/Hypercoaster.h @@ -22,7 +22,7 @@ constexpr RideTypeDescriptor HypercoasterRTD = .TrackPaintFunctions = TrackDrawerDescriptor({ .trackStyle = TrackStyle::corkscrewRollerCoaster, .supportType = MetalSupportType::Tubes, - .enabledTrackGroups = {TrackGroup::straight, TrackGroup::stationEnd, TrackGroup::liftHill, TrackGroup::flatRollBanking, TrackGroup::slope, TrackGroup::slopeSteepUp, TrackGroup::slopeSteepDown, TrackGroup::slopeCurve, TrackGroup::slopeCurveSteep, TrackGroup::sBend, TrackGroup::curveSmall, TrackGroup::curve, TrackGroup::curveLarge, TrackGroup::helixDownBankedHalf, TrackGroup::helixUpBankedHalf, TrackGroup::brakes, TrackGroup::onridePhoto, TrackGroup::blockBrakes, TrackGroup::slopeSteepLong, TrackGroup::diagBrakes, TrackGroup::diagBlockBrakes, TrackGroup::slopeRollBanking, TrackGroup::slopeCurveBanked, TrackGroup::slopeCurveLarge}, + .enabledTrackGroups = {TrackGroup::straight, TrackGroup::stationEnd, TrackGroup::liftHill, TrackGroup::flatRollBanking, TrackGroup::slope, TrackGroup::slopeSteepUp, TrackGroup::slopeSteepDown, TrackGroup::slopeCurve, TrackGroup::slopeCurveSteep, TrackGroup::sBend, TrackGroup::curveSmall, TrackGroup::curve, TrackGroup::curveLarge, TrackGroup::helixDownBankedHalf, TrackGroup::helixUpBankedHalf, TrackGroup::brakes, TrackGroup::onridePhoto, TrackGroup::blockBrakes, TrackGroup::slopeSteepLong, TrackGroup::diagBrakes, TrackGroup::diagBlockBrakes, TrackGroup::slopeRollBanking, TrackGroup::slopeCurveBanked, TrackGroup::slopeCurveLarge, TrackGroup::diagSlopeSteepLong}, .extraTrackGroups = {TrackGroup::verticalLoop, TrackGroup::halfLoop, TrackGroup::corkscrew, TrackGroup::booster}, }), .InvertedTrackPaintFunctions = {}, diff --git a/src/openrct2/ride/rtd/coaster/LSMLaunchedRollerCoaster.h b/src/openrct2/ride/rtd/coaster/LSMLaunchedRollerCoaster.h index 8215adbb56..4268b7cca4 100644 --- a/src/openrct2/ride/rtd/coaster/LSMLaunchedRollerCoaster.h +++ b/src/openrct2/ride/rtd/coaster/LSMLaunchedRollerCoaster.h @@ -22,7 +22,7 @@ constexpr RideTypeDescriptor LSMLaunchedRollerCoasterRTD = .TrackPaintFunctions = TrackDrawerDescriptor({ .trackStyle = TrackStyle::latticeTriangleAlt, .supportType = MetalSupportType::Tubes, - .enabledTrackGroups = {TrackGroup::straight, TrackGroup::stationEnd, TrackGroup::flatRollBanking, TrackGroup::slope, TrackGroup::slopeSteepUp, TrackGroup::slopeSteepDown, TrackGroup::slopeCurve, TrackGroup::slopeCurveSteep, TrackGroup::sBend, TrackGroup::curveSmall, TrackGroup::curve, TrackGroup::curveLarge, TrackGroup::helixDownBankedHalf, TrackGroup::helixUpBankedHalf, TrackGroup::brakes, TrackGroup::diagBrakes, TrackGroup::diagBlockBrakes, TrackGroup::onridePhoto, TrackGroup::blockBrakes, TrackGroup::slopeRollBanking, TrackGroup::slopeSteepLong, TrackGroup::slopeCurveBanked, TrackGroup::slopeCurveLarge, TrackGroup::slopeCurveLargeBanked, TrackGroup::booster, TrackGroup::diagBooster, TrackGroup::poweredLift, TrackGroup::slopeVertical, TrackGroup::curveVertical, TrackGroup::barrelRoll, TrackGroup::quarterLoop, TrackGroup::halfLoop, TrackGroup::halfLoopMedium, TrackGroup::halfLoopLarge, TrackGroup::verticalLoop, TrackGroup::corkscrew, TrackGroup::corkscrewLarge, TrackGroup::zeroGRoll, TrackGroup::zeroGRollLarge }, + .enabledTrackGroups = {TrackGroup::straight, TrackGroup::stationEnd, TrackGroup::flatRollBanking, TrackGroup::slope, TrackGroup::slopeSteepUp, TrackGroup::slopeSteepDown, TrackGroup::slopeCurve, TrackGroup::slopeCurveSteep, TrackGroup::sBend, TrackGroup::curveSmall, TrackGroup::curve, TrackGroup::curveLarge, TrackGroup::helixDownBankedHalf, TrackGroup::helixUpBankedHalf, TrackGroup::brakes, TrackGroup::diagBrakes, TrackGroup::diagBlockBrakes, TrackGroup::onridePhoto, TrackGroup::blockBrakes, TrackGroup::slopeRollBanking, TrackGroup::slopeSteepLong, TrackGroup::slopeCurveBanked, TrackGroup::slopeCurveLarge, TrackGroup::slopeCurveLargeBanked, TrackGroup::booster, TrackGroup::diagBooster, TrackGroup::poweredLift, TrackGroup::slopeVertical, TrackGroup::curveVertical, TrackGroup::barrelRoll, TrackGroup::quarterLoop, TrackGroup::halfLoop, TrackGroup::halfLoopMedium, TrackGroup::halfLoopLarge, TrackGroup::verticalLoop, TrackGroup::corkscrew, TrackGroup::corkscrewLarge, TrackGroup::zeroGRoll, TrackGroup::zeroGRollLarge, TrackGroup::diagSlopeSteepLong, TrackGroup::diveLoop}, .extraTrackGroups = {TrackGroup::liftHill, TrackGroup::liftHillCable}, }), .InvertedTrackPaintFunctions = {}, diff --git a/src/openrct2/ride/rtd/coaster/LayDownRollerCoaster.h b/src/openrct2/ride/rtd/coaster/LayDownRollerCoaster.h index 8cb5072e28..2637ff7a01 100644 --- a/src/openrct2/ride/rtd/coaster/LayDownRollerCoaster.h +++ b/src/openrct2/ride/rtd/coaster/LayDownRollerCoaster.h @@ -23,7 +23,7 @@ constexpr RideTypeDescriptor LayDownRollerCoasterRTD = { .trackStyle = TrackStyle::corkscrewRollerCoaster, .supportType = MetalSupportType::TubesInverted, - .enabledTrackGroups = { TrackGroup::straight, TrackGroup::stationEnd, TrackGroup::liftHill, TrackGroup::flatRollBanking, TrackGroup::verticalLoop, TrackGroup::slope, TrackGroup::slopeSteepUp, TrackGroup::slopeSteepDown, TrackGroup::slopeCurve, TrackGroup::slopeCurveSteep, TrackGroup::sBend, TrackGroup::curveSmall, TrackGroup::curve, TrackGroup::curveLarge, TrackGroup::helixDownBankedHalf, TrackGroup::helixUpBankedHalf, TrackGroup::brakes, TrackGroup::onridePhoto, TrackGroup::blockBrakes, TrackGroup::inlineTwistUninverted, TrackGroup::flyingHalfLoopUninvertedUp, TrackGroup::corkscrewUninverted, TrackGroup::slopeSteepLong, TrackGroup::diagBrakes, TrackGroup::diagBlockBrakes, TrackGroup::slopeRollBanking, TrackGroup::slopeCurveBanked, TrackGroup::slopeCurveLarge }, + .enabledTrackGroups = { TrackGroup::straight, TrackGroup::stationEnd, TrackGroup::liftHill, TrackGroup::flatRollBanking, TrackGroup::verticalLoop, TrackGroup::slope, TrackGroup::slopeSteepUp, TrackGroup::slopeSteepDown, TrackGroup::slopeCurve, TrackGroup::slopeCurveSteep, TrackGroup::sBend, TrackGroup::curveSmall, TrackGroup::curve, TrackGroup::curveLarge, TrackGroup::helixDownBankedHalf, TrackGroup::helixUpBankedHalf, TrackGroup::brakes, TrackGroup::onridePhoto, TrackGroup::blockBrakes, TrackGroup::inlineTwistUninverted, TrackGroup::flyingHalfLoopUninvertedUp, TrackGroup::corkscrewUninverted, TrackGroup::slopeSteepLong, TrackGroup::diagSlopeSteepLong, TrackGroup::diagBrakes, TrackGroup::diagBlockBrakes, TrackGroup::slopeRollBanking, TrackGroup::slopeCurveBanked, TrackGroup::slopeCurveLarge }, .extraTrackGroups = { TrackGroup::flyingHalfLoopUninvertedDown, TrackGroup::booster }, } ), @@ -31,7 +31,7 @@ constexpr RideTypeDescriptor LayDownRollerCoasterRTD = { .trackStyle = TrackStyle::layDownRollerCoasterInverted, .supportType = MetalSupportType::TubesInverted, - .enabledTrackGroups = { TrackGroup::straight, TrackGroup::flatRollBanking, TrackGroup::slope, TrackGroup::slopeSteepUp, TrackGroup::slopeSteepDown, TrackGroup::slopeCurve, TrackGroup::slopeCurveSteep, TrackGroup::sBend, TrackGroup::curveSmall, TrackGroup::curve, TrackGroup::curveLarge, TrackGroup::helixDownBankedQuarter, TrackGroup::helixUpBankedQuarter, TrackGroup::brakes, TrackGroup::onridePhoto, TrackGroup::blockBrakes, TrackGroup::inlineTwistInverted, TrackGroup::flyingHalfLoopInvertedDown, TrackGroup::corkscrewInverted }, + .enabledTrackGroups = { TrackGroup::straight, TrackGroup::flatRollBanking, TrackGroup::slope, TrackGroup::slopeSteepUp, TrackGroup::slopeSteepDown, TrackGroup::slopeCurve, TrackGroup::slopeCurveSteep, TrackGroup::sBend, TrackGroup::curveSmall, TrackGroup::curve, TrackGroup::curveLarge, TrackGroup::helixDownBankedQuarter, TrackGroup::helixUpBankedQuarter, TrackGroup::brakes, TrackGroup::onridePhoto, TrackGroup::blockBrakes, TrackGroup::inlineTwistInverted, TrackGroup::flyingHalfLoopInvertedDown, TrackGroup::corkscrewInverted, TrackGroup::diagBrakes, TrackGroup::diagBlockBrakes }, .extraTrackGroups = { TrackGroup::flyingHalfLoopInvertedUp, TrackGroup::stationEnd, TrackGroup::liftHill }, } ), diff --git a/src/openrct2/ride/rtd/coaster/MultiDimensionRollerCoaster.h b/src/openrct2/ride/rtd/coaster/MultiDimensionRollerCoaster.h index a8f491103d..f84961a7f6 100644 --- a/src/openrct2/ride/rtd/coaster/MultiDimensionRollerCoaster.h +++ b/src/openrct2/ride/rtd/coaster/MultiDimensionRollerCoaster.h @@ -28,7 +28,7 @@ constexpr RideTypeDescriptor MultiDimensionRollerCoasterRTD = .InvertedTrackPaintFunctions = TrackDrawerDescriptor({ .trackStyle = TrackStyle::multiDimensionRollerCoasterInverted, .supportType = MetalSupportType::TubesInverted, - .enabledTrackGroups = {TrackGroup::straight, TrackGroup::flatRollBanking, TrackGroup::slope, TrackGroup::slopeSteepUp, TrackGroup::slopeSteepDown, TrackGroup::sBend, TrackGroup::curveSmall, TrackGroup::curve, TrackGroup::curveLarge, TrackGroup::brakes, TrackGroup::onridePhoto, TrackGroup::slopeVertical, TrackGroup::blockBrakes, TrackGroup::inlineTwistInverted, TrackGroup::quarterLoopInvertedUp, TrackGroup::quarterLoopInvertedDown}, + .enabledTrackGroups = {TrackGroup::straight, TrackGroup::flatRollBanking, TrackGroup::slope, TrackGroup::slopeSteepUp, TrackGroup::slopeSteepDown, TrackGroup::sBend, TrackGroup::curveSmall, TrackGroup::curve, TrackGroup::curveLarge, TrackGroup::brakes, TrackGroup::onridePhoto, TrackGroup::slopeVertical, TrackGroup::blockBrakes, TrackGroup::inlineTwistInverted, TrackGroup::quarterLoopInvertedUp, TrackGroup::quarterLoopInvertedDown, TrackGroup::diagBrakes, TrackGroup::diagBlockBrakes}, .extraTrackGroups = {}, }), .Flags = kRtdFlagsHasThreeColours | kRtdFlagsCommonCoaster | kRtdFlagsCommonCoasterNonAlt | diff --git a/src/openrct2/ride/rtd/coaster/SingleRailRollerCoaster.h b/src/openrct2/ride/rtd/coaster/SingleRailRollerCoaster.h index cbb3e9ddf2..c9eb1f3f15 100644 --- a/src/openrct2/ride/rtd/coaster/SingleRailRollerCoaster.h +++ b/src/openrct2/ride/rtd/coaster/SingleRailRollerCoaster.h @@ -21,8 +21,8 @@ constexpr RideTypeDescriptor SingleRailRollerCoasterRTD = .TrackPaintFunctions = TrackDrawerDescriptor({ .trackStyle = TrackStyle::singleRailRollerCoaster, .supportType = MetalSupportType::Tubes, - .enabledTrackGroups = { TrackGroup::flat, TrackGroup::straight, TrackGroup::stationEnd, TrackGroup::liftHill, TrackGroup::liftHillSteep, TrackGroup::flatRollBanking, TrackGroup::slope, TrackGroup::flatToSteepSlope, TrackGroup::slopeSteepUp, TrackGroup::slopeSteepDown, TrackGroup::slopeCurve, TrackGroup::slopeCurveSteep, TrackGroup::sBend, TrackGroup::curveSmall, TrackGroup::curve, TrackGroup::curveLarge, TrackGroup::corkscrew, TrackGroup::helixDownBankedHalf, TrackGroup::helixUpBankedHalf, TrackGroup::brakes, TrackGroup::onridePhoto, TrackGroup::slopeVertical, TrackGroup::barrelRoll, TrackGroup::slopeCurveBanked, TrackGroup::blockBrakes, TrackGroup::slopeRollBanking, TrackGroup::curveVertical, TrackGroup::quarterLoop, TrackGroup::halfLoop, TrackGroup::halfLoopMedium, TrackGroup::corkscrewLarge, TrackGroup::zeroGRoll, TrackGroup::zeroGRollLarge, TrackGroup::slopeCurveLarge, TrackGroup::diagBrakes, TrackGroup::diagBlockBrakes, TrackGroup::inclinedBrakes }, - .extraTrackGroups = {TrackGroup::slopeSteepLong, TrackGroup::halfLoopLarge}, + .enabledTrackGroups = { TrackGroup::flat, TrackGroup::straight, TrackGroup::stationEnd, TrackGroup::liftHill, TrackGroup::liftHillSteep, TrackGroup::flatRollBanking, TrackGroup::slope, TrackGroup::flatToSteepSlope, TrackGroup::slopeSteepUp, TrackGroup::slopeSteepDown, TrackGroup::slopeCurve, TrackGroup::slopeCurveSteep, TrackGroup::sBend, TrackGroup::curveSmall, TrackGroup::curve, TrackGroup::curveLarge, TrackGroup::corkscrew, TrackGroup::helixDownBankedHalf, TrackGroup::helixUpBankedHalf, TrackGroup::brakes, TrackGroup::onridePhoto, TrackGroup::slopeVertical, TrackGroup::barrelRoll, TrackGroup::slopeCurveBanked, TrackGroup::blockBrakes, TrackGroup::slopeRollBanking, TrackGroup::curveVertical, TrackGroup::quarterLoop, TrackGroup::halfLoop, TrackGroup::halfLoopLarge, TrackGroup::halfLoopMedium, TrackGroup::corkscrewLarge, TrackGroup::zeroGRoll, TrackGroup::zeroGRollLarge, TrackGroup::slopeCurveLarge, TrackGroup::diagBrakes, TrackGroup::diagBlockBrakes, TrackGroup::inclinedBrakes, TrackGroup::diveLoop}, + .extraTrackGroups = {TrackGroup::slopeSteepLong, TrackGroup::diagSlopeSteepLong}, }), .InvertedTrackPaintFunctions = {}, .Flags = kRtdFlagsHasThreeColours | kRtdFlagsCommonCoaster | kRtdFlagsCommonCoasterNonAlt| diff --git a/src/openrct2/ride/rtd/coaster/Steeplechase.h b/src/openrct2/ride/rtd/coaster/Steeplechase.h index e030f7f17c..005d4ed1e3 100644 --- a/src/openrct2/ride/rtd/coaster/Steeplechase.h +++ b/src/openrct2/ride/rtd/coaster/Steeplechase.h @@ -22,7 +22,7 @@ constexpr RideTypeDescriptor SteeplechaseRTD = .TrackPaintFunctions = TrackDrawerDescriptor({ .trackStyle = TrackStyle::steeplechase, .supportType = MetalSupportType::Stick, - .enabledTrackGroups = {TrackGroup::straight, TrackGroup::stationEnd, TrackGroup::liftHill, TrackGroup::slope, TrackGroup::sBend, TrackGroup::curveSmall, TrackGroup::curve, TrackGroup::curveLarge, TrackGroup::brakes, TrackGroup::blockBrakes}, + .enabledTrackGroups = {TrackGroup::straight, TrackGroup::stationEnd, TrackGroup::liftHill, TrackGroup::slope, TrackGroup::sBend, TrackGroup::curveSmall, TrackGroup::curve, TrackGroup::curveLarge, TrackGroup::brakes, TrackGroup::blockBrakes, TrackGroup::diagBrakes, TrackGroup::diagBlockBrakes}, .extraTrackGroups = {}, }), .InvertedTrackPaintFunctions = {}, diff --git a/src/openrct2/ride/rtd/coaster/TwisterRollerCoaster.h b/src/openrct2/ride/rtd/coaster/TwisterRollerCoaster.h index ca8cd094be..bca66759ca 100644 --- a/src/openrct2/ride/rtd/coaster/TwisterRollerCoaster.h +++ b/src/openrct2/ride/rtd/coaster/TwisterRollerCoaster.h @@ -23,7 +23,7 @@ constexpr RideTypeDescriptor TwisterRollerCoasterRTD = .TrackPaintFunctions = TrackDrawerDescriptor({ .trackStyle = TrackStyle::twisterRollerCoaster, .supportType = MetalSupportType::Tubes, - .enabledTrackGroups = {TrackGroup::flat, TrackGroup::straight, TrackGroup::stationEnd, TrackGroup::liftHill, TrackGroup::flatRollBanking, TrackGroup::verticalLoop, TrackGroup::slope, TrackGroup::slopeSteepUp, TrackGroup::slopeSteepDown, TrackGroup::slopeCurve, TrackGroup::slopeCurveSteep, TrackGroup::sBend, TrackGroup::curveSmall, TrackGroup::curve, TrackGroup::curveLarge, TrackGroup::halfLoop, TrackGroup::corkscrew, TrackGroup::helixDownBankedHalf, TrackGroup::helixUpBankedHalf, TrackGroup::brakes, TrackGroup::onridePhoto, TrackGroup::slopeVertical, TrackGroup::barrelRoll, TrackGroup::poweredLift, TrackGroup::halfLoopLarge, TrackGroup::slopeCurveBanked, TrackGroup::blockBrakes, TrackGroup::slopeRollBanking, TrackGroup::slopeSteepLong, TrackGroup::curveVertical, TrackGroup::quarterLoop, TrackGroup::booster, TrackGroup::twist, TrackGroup::diagBrakes, TrackGroup::diagBlockBrakes, TrackGroup::slopeCurveLarge, TrackGroup::corkscrewLarge, TrackGroup::halfLoopMedium, TrackGroup::zeroGRoll, TrackGroup::zeroGRollLarge}, + .enabledTrackGroups = {TrackGroup::flat, TrackGroup::straight, TrackGroup::stationEnd, TrackGroup::liftHill, TrackGroup::flatRollBanking, TrackGroup::verticalLoop, TrackGroup::slope, TrackGroup::slopeSteepUp, TrackGroup::slopeSteepDown, TrackGroup::slopeCurve, TrackGroup::slopeCurveSteep, TrackGroup::sBend, TrackGroup::curveSmall, TrackGroup::curve, TrackGroup::curveLarge, TrackGroup::halfLoop, TrackGroup::corkscrew, TrackGroup::helixDownBankedHalf, TrackGroup::helixUpBankedHalf, TrackGroup::brakes, TrackGroup::onridePhoto, TrackGroup::slopeVertical, TrackGroup::barrelRoll, TrackGroup::poweredLift, TrackGroup::halfLoopLarge, TrackGroup::slopeCurveBanked, TrackGroup::blockBrakes, TrackGroup::slopeRollBanking, TrackGroup::slopeSteepLong, TrackGroup::curveVertical, TrackGroup::quarterLoop, TrackGroup::booster, TrackGroup::twist, TrackGroup::diagBrakes, TrackGroup::diagBlockBrakes, TrackGroup::slopeCurveLarge, TrackGroup::corkscrewLarge, TrackGroup::halfLoopMedium, TrackGroup::zeroGRoll, TrackGroup::zeroGRollLarge, TrackGroup::diagSlopeSteepLong, TrackGroup::diveLoop}, .extraTrackGroups = {TrackGroup::liftHillSteep, TrackGroup::brakeForDrop}, }), .InvertedTrackPaintFunctions = {}, diff --git a/src/openrct2/ride/rtd/coaster/VerticalDropCoaster.h b/src/openrct2/ride/rtd/coaster/VerticalDropCoaster.h index ce5007ceb5..77f88d4464 100644 --- a/src/openrct2/ride/rtd/coaster/VerticalDropCoaster.h +++ b/src/openrct2/ride/rtd/coaster/VerticalDropCoaster.h @@ -23,8 +23,8 @@ constexpr RideTypeDescriptor VerticalDropCoasterRTD = .TrackPaintFunctions = TrackDrawerDescriptor({ .trackStyle = TrackStyle::twisterRollerCoaster, .supportType = MetalSupportType::Boxed, - .enabledTrackGroups = {TrackGroup::flat, TrackGroup::straight, TrackGroup::stationEnd, TrackGroup::liftHill, TrackGroup::liftHillSteep, TrackGroup::flatRollBanking, TrackGroup::verticalLoop, TrackGroup::slope, TrackGroup::slopeSteepUp, TrackGroup::slopeSteepDown, TrackGroup::flatToSteepSlope, TrackGroup::slopeCurve, TrackGroup::slopeCurveSteep, TrackGroup::sBend, TrackGroup::curveSmall, TrackGroup::curve, TrackGroup::curveLarge, TrackGroup::helixDownBankedHalf, TrackGroup::helixUpBankedHalf, TrackGroup::brakes, TrackGroup::onridePhoto, TrackGroup::slopeVertical, TrackGroup::slopeCurveBanked, TrackGroup::blockBrakes, TrackGroup::slopeRollBanking, TrackGroup::curveVertical, TrackGroup::halfLoopLarge, TrackGroup::brakeForDrop, TrackGroup::diagBrakes, TrackGroup::diagBlockBrakes, TrackGroup::slopeCurveLarge, TrackGroup::halfLoopMedium, TrackGroup::zeroGRoll, TrackGroup::zeroGRollLarge, TrackGroup::corkscrew, TrackGroup::corkscrewLarge}, - .extraTrackGroups = {TrackGroup::halfLoop, TrackGroup::barrelRoll, TrackGroup::poweredLift, TrackGroup::halfLoopLarge, TrackGroup::quarterLoop, TrackGroup::booster, TrackGroup::twist}, + .enabledTrackGroups = {TrackGroup::flat, TrackGroup::straight, TrackGroup::stationEnd, TrackGroup::liftHill, TrackGroup::liftHillSteep, TrackGroup::flatRollBanking, TrackGroup::verticalLoop, TrackGroup::slope, TrackGroup::slopeSteepUp, TrackGroup::slopeSteepDown, TrackGroup::flatToSteepSlope, TrackGroup::slopeCurve, TrackGroup::slopeCurveSteep, TrackGroup::sBend, TrackGroup::curveSmall, TrackGroup::curve, TrackGroup::curveLarge, TrackGroup::helixDownBankedHalf, TrackGroup::helixUpBankedHalf, TrackGroup::brakes, TrackGroup::onridePhoto, TrackGroup::slopeVertical, TrackGroup::slopeCurveBanked, TrackGroup::blockBrakes, TrackGroup::slopeRollBanking, TrackGroup::curveVertical, TrackGroup::halfLoopLarge, TrackGroup::brakeForDrop, TrackGroup::diagBrakes, TrackGroup::diagBlockBrakes, TrackGroup::slopeCurveLarge, TrackGroup::halfLoopMedium, TrackGroup::zeroGRoll, TrackGroup::zeroGRollLarge, TrackGroup::corkscrew, TrackGroup::corkscrewLarge, TrackGroup::diveLoop}, + .extraTrackGroups = {TrackGroup::halfLoop, TrackGroup::barrelRoll, TrackGroup::poweredLift, TrackGroup::halfLoopLarge, TrackGroup::quarterLoop, TrackGroup::booster, TrackGroup::twist, TrackGroup::slopeSteepLong, TrackGroup::diagSlopeSteepLong}, }), .InvertedTrackPaintFunctions = {}, .Flags = kRtdFlagsHasThreeColours | kRtdFlagsCommonCoaster | kRtdFlagsCommonCoasterNonAlt | diff --git a/src/openrct2/sprites.h b/src/openrct2/sprites.h index 8732db0c23..1703c4301d 100644 --- a/src/openrct2/sprites.h +++ b/src/openrct2/sprites.h @@ -1298,7 +1298,9 @@ enum : ImageIndex SPR_G2_LATTICE_TRIANGLE_TRACK_SMALL_FLAT_TO_STEEP = SPR_G2_LATTICE_TRIANGLE_TRACK_LARGE_ZERO_G_ROLL + 40, SPR_G2_LATTICE_TRIANGLE_TRACK_GENTLE_LARGE_CURVE = SPR_G2_LATTICE_TRIANGLE_TRACK_SMALL_FLAT_TO_STEEP + 20, SPR_G2_LATTICE_TRIANGLE_TRACK_GENTLE_LARGE_CURVE_BANKED = SPR_G2_LATTICE_TRIANGLE_TRACK_GENTLE_LARGE_CURVE + 64, - SPR_G2_LATTICE_TRIANGLE_TRACK_END = SPR_G2_LATTICE_TRIANGLE_TRACK_GENTLE_LARGE_CURVE_BANKED + 128, + SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL = SPR_G2_LATTICE_TRIANGLE_TRACK_GENTLE_LARGE_CURVE_BANKED + 128, + SPR_G2_LATTICE_TRIANGLE_TRACK_DIVE_LOOP = SPR_G2_LATTICE_TRIANGLE_TRACK_FLAT_TO_STEEP_DIAGONAL + 24, + SPR_G2_LATTICE_TRIANGLE_TRACK_END = SPR_G2_LATTICE_TRIANGLE_TRACK_DIVE_LOOP + 32, SPR_G2_MINI_RC_BEGIN = SPR_G2_LATTICE_TRIANGLE_TRACK_END, SPR_G2_MINI_RC_BOOSTER_NE_SW = SPR_G2_MINI_RC_BEGIN, @@ -1315,7 +1317,9 @@ enum : ImageIndex SPR_G2_BM_TRACK_MEDIUM_HALF_LOOP = SPR_G2_BM_TRACK_LARGE_CORKSCREW + 40, SPR_G2_BM_TRACK_ZERO_G_ROLL = SPR_G2_BM_TRACK_MEDIUM_HALF_LOOP + 44, SPR_G2_BM_TRACK_LARGE_ZERO_G_ROLL = SPR_G2_BM_TRACK_ZERO_G_ROLL + 32, - SPR_G2_BM_RC_END = SPR_G2_BM_TRACK_LARGE_ZERO_G_ROLL + 40, + SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL = SPR_G2_BM_TRACK_LARGE_ZERO_G_ROLL + 40, + SPR_G2_BM_TRACK_DIVE_LOOP = SPR_G2_BM_TRACK_FLAT_TO_STEEP_DIAGONAL + 24, + SPR_G2_BM_RC_END = SPR_G2_BM_TRACK_DIVE_LOOP + 32, SPR_G2_MINIATURE_RAILWAY_BEGIN = SPR_G2_BM_RC_END, SPR_G2_MINIATURE_RAILWAY_QUARTER_TURN_3_TILES_SW_SE_PART_3 = SPR_G2_MINIATURE_RAILWAY_BEGIN, @@ -1497,7 +1501,9 @@ enum : ImageIndex SPR_G2_CORKSCREW_TRACK_BARREL_ROLL = SPR_G2_CORKSCREW_TRACK_LARGE_HALF_LOOP + 64, SPR_G2_CORKSCREW_TRACK_ZERO_G_ROLL = SPR_G2_CORKSCREW_TRACK_BARREL_ROLL + 48, SPR_G2_CORKSCREW_TRACK_LARGE_ZERO_G_ROLL = SPR_G2_CORKSCREW_TRACK_ZERO_G_ROLL + 40, - SPR_G2_CORKSCREW_RC_END = SPR_G2_CORKSCREW_TRACK_LARGE_ZERO_G_ROLL + 58, + SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL = SPR_G2_CORKSCREW_TRACK_LARGE_ZERO_G_ROLL + 58, + SPR_G2_CORKSCREW_TRACK_DIVE_LOOP = SPR_G2_CORKSCREW_TRACK_FLAT_TO_STEEP_DIAGONAL + 24, + SPR_G2_CORKSCREW_RC_END = SPR_G2_CORKSCREW_TRACK_DIVE_LOOP + 32, SPR_G2_LIM_LAUNCHED_TRACK_BEGIN = SPR_G2_CORKSCREW_RC_END, SPR_G2_LIM_LAUNCHED_TRACK_BARREL_ROLL = SPR_G2_LIM_LAUNCHED_TRACK_BEGIN + 0, @@ -1642,7 +1648,9 @@ enum : ImageIndex SPR_G2_SINGLE_RAIL_TRACK_SMALL_FLAT_TO_STEEP = SPR_G2_SINGLE_RAIL_TRACK_LARGE_ZERO_G_ROLL + 40, SPR_G2_SINGLE_RAIL_TRACK_GENTLE_LARGE_CURVE = SPR_G2_SINGLE_RAIL_TRACK_SMALL_FLAT_TO_STEEP + 20, SPR_G2_SINGLE_RAIL_TRACK_GENTLE_LARGE_CURVE_BANKED = SPR_G2_SINGLE_RAIL_TRACK_GENTLE_LARGE_CURVE + 64, - SPR_G2_SINGLE_RAIL_LIFT_BEGIN = SPR_G2_SINGLE_RAIL_TRACK_GENTLE_LARGE_CURVE_BANKED + 128, + SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL = SPR_G2_SINGLE_RAIL_TRACK_GENTLE_LARGE_CURVE_BANKED + 128, + SPR_G2_SINGLE_RAIL_TRACK_DIVE_LOOP = SPR_G2_SINGLE_RAIL_TRACK_FLAT_TO_STEEP_DIAGONAL + 24, + SPR_G2_SINGLE_RAIL_LIFT_BEGIN = SPR_G2_SINGLE_RAIL_TRACK_DIVE_LOOP + 32, SPR_G2_SINGLE_RAIL_LIFT_TRACK_FLAT = SPR_G2_SINGLE_RAIL_LIFT_BEGIN, SPR_G2_SINGLE_RAIL_LIFT_TRACK_GENTLE = SPR_G2_SINGLE_RAIL_LIFT_TRACK_FLAT + 4, SPR_G2_SINGLE_RAIL_LIFT_TRACK_STEEP = SPR_G2_SINGLE_RAIL_LIFT_TRACK_GENTLE + 12, @@ -1690,6 +1698,7 @@ enum : ImageIndex SPR_G2_CORKSCREW_BOOSTER_NE_SW_2, SPR_G2_CORKSCREW_BOOSTER_NW_SE_2, SPR_G2_OPAQUE_WATER_OVERLAY, + SPR_G2_END = SPR_G2_OPAQUE_WATER_OVERLAY + 5, SPR_CSG_BEGIN = SPR_G2_END, diff --git a/src/openrct2/ui/DummyWindowManager.cpp b/src/openrct2/ui/DummyWindowManager.cpp index ec19f7c25f..383a5c7b6a 100644 --- a/src/openrct2/ui/DummyWindowManager.cpp +++ b/src/openrct2/ui/DummyWindowManager.cpp @@ -87,7 +87,7 @@ namespace OpenRCT2::Ui } WidgetIndex FindWidgetFromPoint(WindowBase& w, const ScreenCoordsXY& screenCoords) override { - return -1; + return kWidgetIndexNull; } }; diff --git a/src/openrct2/windows/Intent.h b/src/openrct2/windows/Intent.h index 0f6068c608..3439d33442 100644 --- a/src/openrct2/windows/Intent.h +++ b/src/openrct2/windows/Intent.h @@ -17,112 +17,115 @@ #include #include -enum IntentAction +namespace OpenRCT2 { - INTENT_ACTION_MAP, - INTENT_ACTION_NEW_RIDE_OF_TYPE, - INTENT_ACTION_REFRESH_CAMPAIGN_RIDE_LIST, - INTENT_ACTION_REFRESH_NEW_RIDES, - INTENT_ACTION_REFRESH_RIDE_LIST, - INTENT_ACTION_UPDATE_MAZE_CONSTRUCTION, - INTENT_ACTION_RIDE_CONSTRUCTION_FOCUS, - INTENT_ACTION_RIDE_CONSTRUCTION_UPDATE_PIECES, - INTENT_ACTION_RIDE_CONSTRUCTION_UPDATE_ACTIVE_ELEMENTS, - INTENT_ACTION_INIT_SCENERY, - INTENT_ACTION_SET_DEFAULT_SCENERY_CONFIG, - INTENT_ACTION_REFRESH_SCENERY, - INTENT_ACTION_INVALIDATE_TICKER_NEWS, - INTENT_ACTION_REFRESH_GUEST_LIST, - INTENT_ACTION_CLEAR_TILE_INSPECTOR_CLIPBOARD, - INTENT_ACTION_REFRESH_STAFF_LIST, - INTENT_ACTION_INVALIDATE_VEHICLE_WINDOW, - INTENT_ACTION_RIDE_PAINT_RESET_VEHICLE, - INTENT_ACTION_UPDATE_CLIMATE, - INTENT_ACTION_UPDATE_GUEST_COUNT, - INTENT_ACTION_UPDATE_PARK_RATING, - INTENT_ACTION_UPDATE_DATE, - INTENT_ACTION_UPDATE_CASH, - INTENT_ACTION_UPDATE_BANNER, - INTENT_ACTION_UPDATE_RESEARCH, - INTENT_ACTION_UPDATE_VEHICLE_SOUNDS, - INTENT_ACTION_SET_MAP_TOOLTIP, - INTENT_ACTION_NEW_SCENERY, - INTENT_ACTION_TILE_MODIFY, - INTENT_ACTION_PROGRESS_OPEN, - INTENT_ACTION_PROGRESS_SET, - INTENT_ACTION_PROGRESS_CLOSE, - INTENT_ACTION_REMOVE_PROVISIONAL_ELEMENTS, - INTENT_ACTION_RESTORE_PROVISIONAL_ELEMENTS, - INTENT_ACTION_REMOVE_PROVISIONAL_FOOTPATH, - INTENT_ACTION_REMOVE_PROVISIONAL_TRACK_PIECE, - - INTENT_ACTION_NULL = 255, -}; - -// The maximum amount of data the Intent can hold, 8 should be sufficient, raise this if needed. -static constexpr size_t kIntentMaxDataSlots = 8; - -using IntentData = std::variant; -using IntentDataEntry = std::pair; -using IntentDataStorage = sfl::static_vector; - -class Intent -{ - WindowClass _Class{ WindowClass::Null }; - WindowDetail _WindowDetail{ WD_NULL }; - IntentAction _Action{ INTENT_ACTION_NULL }; - IntentDataStorage _Data; - -public: - explicit Intent(WindowClass windowClass); - explicit Intent(WindowDetail windowDetail); - explicit Intent(IntentAction windowclass); - - WindowClass GetWindowClass() const; - WindowDetail GetWindowDetail() const; - IntentAction GetAction() const; - - void* GetPointerExtra(uint32_t key) const; - std::string GetStringExtra(uint32_t key) const; - uint32_t GetUIntExtra(uint32_t key) const; - int32_t GetSIntExtra(uint32_t key) const; - CloseCallback GetCloseCallbackExtra(uint32_t key) const; - - Intent* PutExtra(uint32_t key, uint32_t value); - Intent* PutExtra(uint32_t key, void* value); - Intent* PutExtra(uint32_t key, int32_t value); - Intent* PutExtra(uint32_t key, std::string value); - Intent* PutExtra(uint32_t key, CloseCallback value); - - template - Intent* PutExtra(uint32_t key, const TIdentifier& value) + enum IntentAction { - const auto val = value.ToUnderlying(); - return PutExtra(key, static_cast(val)); - } -}; + INTENT_ACTION_MAP, + INTENT_ACTION_NEW_RIDE_OF_TYPE, + INTENT_ACTION_REFRESH_CAMPAIGN_RIDE_LIST, + INTENT_ACTION_REFRESH_NEW_RIDES, + INTENT_ACTION_REFRESH_RIDE_LIST, + INTENT_ACTION_UPDATE_MAZE_CONSTRUCTION, + INTENT_ACTION_RIDE_CONSTRUCTION_FOCUS, + INTENT_ACTION_RIDE_CONSTRUCTION_UPDATE_PIECES, + INTENT_ACTION_RIDE_CONSTRUCTION_UPDATE_ACTIVE_ELEMENTS, + INTENT_ACTION_INIT_SCENERY, + INTENT_ACTION_SET_DEFAULT_SCENERY_CONFIG, + INTENT_ACTION_REFRESH_SCENERY, + INTENT_ACTION_INVALIDATE_TICKER_NEWS, + INTENT_ACTION_REFRESH_GUEST_LIST, + INTENT_ACTION_CLEAR_TILE_INSPECTOR_CLIPBOARD, + INTENT_ACTION_REFRESH_STAFF_LIST, + INTENT_ACTION_INVALIDATE_VEHICLE_WINDOW, + INTENT_ACTION_RIDE_PAINT_RESET_VEHICLE, + INTENT_ACTION_UPDATE_CLIMATE, + INTENT_ACTION_UPDATE_GUEST_COUNT, + INTENT_ACTION_UPDATE_PARK_RATING, + INTENT_ACTION_UPDATE_DATE, + INTENT_ACTION_UPDATE_CASH, + INTENT_ACTION_UPDATE_BANNER, + INTENT_ACTION_UPDATE_RESEARCH, + INTENT_ACTION_UPDATE_VEHICLE_SOUNDS, + INTENT_ACTION_SET_MAP_TOOLTIP, + INTENT_ACTION_NEW_SCENERY, + INTENT_ACTION_TILE_MODIFY, + INTENT_ACTION_PROGRESS_OPEN, + INTENT_ACTION_PROGRESS_SET, + INTENT_ACTION_PROGRESS_CLOSE, + INTENT_ACTION_REMOVE_PROVISIONAL_ELEMENTS, + INTENT_ACTION_RESTORE_PROVISIONAL_ELEMENTS, + INTENT_ACTION_REMOVE_PROVISIONAL_FOOTPATH, + INTENT_ACTION_REMOVE_PROVISIONAL_TRACK_PIECE, -enum -{ - INTENT_EXTRA_GUEST_LIST_FILTER, - INTENT_EXTRA_RIDE_ID, - INTENT_EXTRA_PATH, - INTENT_EXTRA_PEEP, - INTENT_EXTRA_LOADSAVE_TYPE, - INTENT_EXTRA_CALLBACK, - INTENT_EXTRA_TRACK_DESIGN, - INTENT_EXTRA_RIDE_TYPE, - INTENT_EXTRA_RIDE_ENTRY_INDEX, - INTENT_EXTRA_TILE_ELEMENT, - INTENT_EXTRA_VEHICLE, - INTENT_EXTRA_MESSAGE, - INTENT_EXTRA_LIST, - INTENT_EXTRA_LIST_COUNT, - INTENT_EXTRA_PAGE, - INTENT_EXTRA_BANNER_INDEX, - INTENT_EXTRA_FORMATTER, - INTENT_EXTRA_SCENERY_GROUP_ENTRY_INDEX, - INTENT_EXTRA_PROGRESS_OFFSET, - INTENT_EXTRA_PROGRESS_TOTAL, - INTENT_EXTRA_STRING_ID, -}; + INTENT_ACTION_NULL = 255, + }; + + // The maximum amount of data the Intent can hold, 8 should be sufficient, raise this if needed. + static constexpr size_t kIntentMaxDataSlots = 8; + + using IntentData = std::variant; + using IntentDataEntry = std::pair; + using IntentDataStorage = sfl::static_vector; + + class Intent + { + WindowClass _Class{ WindowClass::Null }; + WindowDetail _WindowDetail{ WD_NULL }; + IntentAction _Action{ INTENT_ACTION_NULL }; + IntentDataStorage _Data; + + public: + explicit Intent(WindowClass windowClass); + explicit Intent(WindowDetail windowDetail); + explicit Intent(IntentAction windowclass); + + WindowClass GetWindowClass() const; + WindowDetail GetWindowDetail() const; + IntentAction GetAction() const; + + void* GetPointerExtra(uint32_t key) const; + std::string GetStringExtra(uint32_t key) const; + uint32_t GetUIntExtra(uint32_t key) const; + int32_t GetSIntExtra(uint32_t key) const; + CloseCallback GetCloseCallbackExtra(uint32_t key) const; + + Intent* PutExtra(uint32_t key, uint32_t value); + Intent* PutExtra(uint32_t key, void* value); + Intent* PutExtra(uint32_t key, int32_t value); + Intent* PutExtra(uint32_t key, std::string value); + Intent* PutExtra(uint32_t key, CloseCallback value); + + template + Intent* PutExtra(uint32_t key, const TIdentifier& value) + { + const auto val = value.ToUnderlying(); + return PutExtra(key, static_cast(val)); + } + }; + + enum + { + INTENT_EXTRA_GUEST_LIST_FILTER, + INTENT_EXTRA_RIDE_ID, + INTENT_EXTRA_PATH, + INTENT_EXTRA_PEEP, + INTENT_EXTRA_LOADSAVE_TYPE, + INTENT_EXTRA_CALLBACK, + INTENT_EXTRA_TRACK_DESIGN, + INTENT_EXTRA_RIDE_TYPE, + INTENT_EXTRA_RIDE_ENTRY_INDEX, + INTENT_EXTRA_TILE_ELEMENT, + INTENT_EXTRA_VEHICLE, + INTENT_EXTRA_MESSAGE, + INTENT_EXTRA_LIST, + INTENT_EXTRA_LIST_COUNT, + INTENT_EXTRA_PAGE, + INTENT_EXTRA_BANNER_INDEX, + INTENT_EXTRA_FORMATTER, + INTENT_EXTRA_SCENERY_GROUP_ENTRY_INDEX, + INTENT_EXTRA_PROGRESS_OFFSET, + INTENT_EXTRA_PROGRESS_TOTAL, + INTENT_EXTRA_STRING_ID, + }; +} // namespace OpenRCT2 diff --git a/src/openrct2/world/Map.cpp b/src/openrct2/world/Map.cpp index 7ed0c325f3..cc1a0efd54 100644 --- a/src/openrct2/world/Map.cpp +++ b/src/openrct2/world/Map.cpp @@ -2352,7 +2352,7 @@ void ShiftMap(const TileCoordsXY& amount) // Rides for (auto& ride : GetRideManager()) { - auto& stations = ride.GetStations(); + auto stations = ride.GetStations(); for (auto& station : stations) { shiftIfNotNull(station.Start, amountToMove);