diff --git a/CMakeLists.txt b/CMakeLists.txt index 74762470ce..32be94c0cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,11 +24,14 @@ set (ORCT2_RESOURCE_DIR ${CMAKE_INSTALL_PREFIX}/share/${PROJECT}/) project(${PROJECT}) add_definitions(-DORCT2_RESOURCE_DIR="${ORCT2_RESOURCE_DIR}") +add_definitions(-DHAVE_CONFIG_H) -# include lodepng header -include_directories("lodepng/") +# include lib +include_directories("lib/") +# include speex header +include_directories("lib/libspeex/") # add source files -file(GLOB_RECURSE ORCT2_SOURCES "src/*.c" "lodepng/*.c") +file(GLOB_RECURSE ORCT2_SOURCES "src/*.c" "src/*.cpp" "lib/*.c") if (UNIX) # force 32bit build for now and set necessary flags to compile code as is diff --git a/build.sh b/build.sh index 965c72cbbf..b69543ebd8 100755 --- a/build.sh +++ b/build.sh @@ -11,6 +11,10 @@ pushd build make popd +if [[ ! -h openrct2.dll ]]; then + ln -s build/openrct2.dll openrct2.dll +fi + if [[ -t 1 ]]; then echo -e "\nDone! Run OpenRCT2 by typing:\n\n\033[95mwine openrct2.exe\n\033[0m" else diff --git a/data/language/dutch.txt b/data/language/dutch.txt index 7c7210d07c..12b6dde7aa 100644 --- a/data/language/dutch.txt +++ b/data/language/dutch.txt @@ -5,13 +5,13 @@ STR_0003 :Attractie STR_0004 :Omgekeerde schommelachtbaan STR_0005 :Attractie STR_0006 :Juniorachtbaan -STR_0007 :Miniatuur spoorbaan +STR_0007 :Miniatuurspoorweg STR_0008 :Monorail STR_0009 :Omgekeerde miniachtbaan STR_0010 :Attractie STR_0011 :Attractie STR_0012 :Attractie -STR_0013 :Rit in een karretje +STR_0013 :Autorondrit STR_0014 :Attractie STR_0015 :Attractie STR_0016 :Attractie @@ -66,7 +66,7 @@ STR_0064 :Attractie STR_0065 :Omgekeerde monorail STR_0066 :Attractie STR_0067 :Attractie -STR_0068 :Heartline-kurkentrekkerachtbaan +STR_0068 :Heartline-twisterachtbaan STR_0069 :Attractie STR_0070 :Attractie STR_0071 :Attractie @@ -512,12 +512,12 @@ STR_0510 : STR_0511 : STR_0512 : STR_0513 : -STR_0514 :Karretjes die onder de baan hangen zwaaien naar buiten in bochten +STR_0514 :Treinen hangen onder de baan en zwaaien naar buiten in bochten STR_0515 : STR_0516 :Een rustige achtbaan voor bezoekers die nog niet in engere attracties durven -STR_0517 :Passagiers rijden in miniatuurtreinen over een smalspoorbaan +STR_0517 :Passagiers rijden in miniatuurtreinen over een smalspoorweg STR_0518 :Passagiers rijden in elektrische treinen over een monorailbaan -STR_0519 :Passagiers zitten in kleine karretjes onder een enkelrailsbaan en zwaaien naar buiten zwaaien in bochten +STR_0519 :Passagiers zitten in kleine karretjes die onder een enkele rail hangen en naar buiten zwaaien in de bochten STR_0520 : STR_0521 : STR_0522 : @@ -525,7 +525,7 @@ STR_0523 :Bezoekers rijden langzaam over een baan in aangedreven karretjes STR_0524 : STR_0525 : STR_0526 : -STR_0527 :Een stalen achtbaan die verticale loopings kan maken +STR_0527 :Een soepele stalen achtbaan die verticale loopings kan maken STR_0528 : STR_0529 : STR_0530 :Stoeltjes hangen aan een continu draaiende stalen kabel die van het ene uiteinde van de baan naar het andere loopt, en daarna weer terug @@ -552,7 +552,7 @@ STR_0550 : STR_0551 : STR_0552 : STR_0553 : -STR_0554 :Het karretje word het station uitversnelt over een lange rechte baan door middel van lineaire inductiemotoren, om daarna recht omhoog te gaan en weer terug te vallen richting het station +STR_0554 :Het karretje wordt het station uitgelanceerd over een lange rechte baan door middel van lineaire inductiemotoren, om daarna recht omhoog te gaan en weer terug te vallen richting het station STR_0555 : STR_0556 : STR_0557 : @@ -561,22 +561,22 @@ STR_0559 : STR_0560 : STR_0561 : STR_0562 : -STR_0563 :Zittend in comfortable treintjes met enkel een simpele schootbeugel genieten bezoeker van grote glijdende afdalingen en kronkelende stukken baan, evenals genoeg 'air time' over de heuvels -STR_0564 :Over een houten baan donderend is deze achtbaan snel, ruig, luidruchting, en geeft hij rijders een gevoel van controleverleis met meer dan genoeg 'air time' -STR_0565 :Een simpele houten achtbaan die enkel in staat is rustige hellingen en bochten te bedwingen, de karretjes worden alleen maar op de baan gehouden door middel van zijfrictie wieltjes en zwaartekracht -STR_0566 :Individuele achtbaankarretjes vliegen door een dichte zig-zag baan met scherpe bochten en korte scherpe afdalingen -STR_0567 :Zittend in speciale stoeltjes die aan bijde kanten van de baan hangen worden rijders hals over de kop gegooid terwijl de diepe afdalingen maken en door menige loopings vliegen +STR_0563 :Bezoekers zitten in comfortabele treinen met enkel een schootbeugel en gaan door soepel door grote afdalingen en kronkelende stukken baan, met veel 'airtime' in de heuvels +STR_0564 :Deze over een houten baan lopende achtbaan is snel, ruw, luidruchting en geeft het gevoel van controleverlies met veel 'airtime' +STR_0565 :Een simpele houten achtbaan die enkel in staat is rustige hellingen en bochten te bedwingen, de karretjes worden enkel op de baan gehouden door middel van zijfrictiewielen en zwaartekracht +STR_0566 :Losse karretjes rijden over een kronkelende baan scherpe bochten en korte felle afdalingen +STR_0567 :Bezoekers zitten in stoelen aan beide kanten van de baan, en draaien alle kanten op terwijl ze door de diepe afdalingen gaan en door diverse omkeringen. STR_0568 : -STR_0569 :Hangend in speciale harnassen onder de baan krijgen bezoekers het gevoel alsof ze een vogel op de wind zijn terwijl ze door de lucht heen zwiepen en vliegen +STR_0569 :Bezoekers zitten in een speciaal tuig onder de baan en krijgen zo de ervaring dat ze vliegen STR_0570 : STR_0571 : STR_0572 : STR_0573 : STR_0574 : -STR_0575 :Aangedreven treintjes hangen van een enkele rail en transporteren mensen door het park heen +STR_0575 :Aangedreven treinen hangen aan een enkele rail en vervoeren mensen door het park heen STR_0576 : STR_0577 : -STR_0578 :Karretjes lopen over een baan omgeven door hoepels en ondergaan steile afdalingen en heartline kurkentrekkers +STR_0578 :Karretjes lopen in een baan omgeven door hoepels en gaan door steile afdalingen en heartline-twists STR_0579 : STR_0580 : STR_0581 : @@ -584,7 +584,7 @@ STR_0582 : STR_0583 : STR_0584 : STR_0585 : -STR_0586 :Bootvormige karretjes lopen over achtbaan rails waardoor ze hellende bochten en diepe afdalingen kunnen maken, waarna ze in bakken water neerplonsen voor rustige rivier secties van de baan +STR_0586 :Bootvormige karretjes lopen over achtbaanrails waardoor ze hellende bochten en diepe afdalingen kunnen maken, waarna ze in bakken water neerplonzen en rustig een stukje kunnen varen STR_0587 : STR_0588 : STR_0589 : @@ -597,7 +597,7 @@ STR_0595 : STR_0596 : STR_0597 : STR_0598 : -STR_0599 :Een compacte achtbaan met individuele karretjes, scherpe bochten, en steile afdalingen +STR_0599 :Een compacte achtbaan met individuele karretjes en steile, kronkelende afdalingen STR_0600 : STR_0601 : STR_0602 : @@ -907,7 +907,7 @@ STR_0905 :{SMALLFONT}{BLACK}Bocht naar rechts (grote radius) STR_0906 :{SMALLFONT}{BLACK}Recht stuk STR_0907 :Helling STR_0908 :Roll/Banking -STR_0909 :Stoeldraaing +STR_0909 :Stoelrot. STR_0910 :{SMALLFONT}{BLACK}Roll voor bocht naar links STR_0911 :{SMALLFONT}{BLACK}Roll voor bocht naar rechts STR_0912 :{SMALLFONT}{BLACK}Geen roll @@ -1662,7 +1662,7 @@ STR_1660 :{WINDOW_COLOUR_2}{BLACK}meer dan {COMMA16} STR_1661 :{WINDOW_COLOUR_2}Misselijkheidstolerantie: {BLACK}{STRINGID} STR_1662 :{WINDOW_COLOUR_2}Stemming: STR_1663 :{WINDOW_COLOUR_2}Misselijkheid: -STR_1664 :{WINDOW_COLOUR_2}Blijheid: +STR_1664 :{WINDOW_COLOUR_2}Energie: STR_1665 :{WINDOW_COLOUR_2}Honger: STR_1666 :{WINDOW_COLOUR_2}Dorst: STR_1667 :{WINDOW_COLOUR_2}WC-behoefte: @@ -1698,10 +1698,10 @@ STR_1696 :{SMALLFONT}{BLACK}Klantinformatie STR_1697 :Dit kan niet op wachtrijen worden geplaatst STR_1698 :Dit kan alleen op wachtrijen worden geplaatst STR_1699 :Teveel personen in het spel -STR_1700 :Nieuwe klusjesman aannemen -STR_1701 :Nieuwe monteur aannemen -STR_1702 :Nieuwe bewaker aannemen -STR_1703 :Nieuwe entertainer aannemen +STR_1700 :Klusjesman aannemen... +STR_1701 :Monteur aannemen... +STR_1702 :Bewaker aannemen... +STR_1703 :Entertainer aannemen... STR_1704 :Kan geen nieuwe werknemer aannemen... STR_1705 :{SMALLFONT}{BLACK}Deze werknemer ontslaan STR_1706 :{SMALLFONT}{BLACK}Deze persoon naar een andere locatie verplaatsen @@ -1818,8 +1818,8 @@ STR_1816 :{SMALLFONT}{BLACK}Selecteer het type informatie dat je in de gasten STR_1817 :({COMMA16}) STR_1818 :{WINDOW_COLOUR_2}Alle bezoekers STR_1819 :{WINDOW_COLOUR_2}Alle bezoekers (samengevat) -STR_1820 :{WINDOW_COLOUR_2}Bezoekers die {STRINGID} -STR_1821 :{WINDOW_COLOUR_2}Bezoekers die {STRINGID} denken +STR_1820 :{WINDOW_COLOUR_2}Bezoekers met de volgende status: {STRINGID} +STR_1821 :{WINDOW_COLOUR_2}Bezoekers met de volgende gedachte: {STRINGID} STR_1822 :{WINDOW_COLOUR_2}Bezoekers met gedachten over {POP16}{STRINGID} STR_1823 :{SMALLFONT}{BLACK}Toon de gedachten van bezoekers over deze attractie STR_1824 :{SMALLFONT}{BLACK}Toon de bezoekers in deze attractie @@ -1891,7 +1891,7 @@ STR_1889 :{WINDOW_COLOUR_2}Stilstandtijd: {MOVE_X}{255}{BLACK}{COMMA16}% STR_1890 :{SMALLFONT}{BLACK}Selecteer hoe vaak een monteur deze attractie moet inspecteren STR_1891 :Nog geen {STRINGID} in het park! STR_1892 :RollerCoaster Tycoon 2 -STR_1893 :Voer je CD van RollerCoaster Tycoon 2 in het volgende stationCD in the folLaaging drive: +STR_1893 :Voer je CD van RollerCoaster Tycoon 2 in het volgende station in: STR_1894 :{WINDOW_COLOUR_2}{STRINGID} verkocht: {BLACK}{COMMA32} STR_1895 :{SMALLFONT}{BLACK}Nieuwe attractie bouwen STR_1896 :{WINDOW_COLOUR_2}Uitgaven/Inkomsten @@ -1921,7 +1921,7 @@ STR_1919 :Onvoldoende contant geld beschikbaar! STR_1920 :Kan geen lening terugbetalen! STR_1921 :{SMALLFONT}{BLACK}Een nieuw spel starten STR_1922 :{SMALLFONT}{BLACK}Verder gaan aan een opgeslagen spel -STR_1923 :{SMALLFONT}{BLACK}Snelcursus tonen +STR_1923 :{SMALLFONT}{BLACK}Tutorial tonen STR_1924 :{SMALLFONT}{BLACK}Afsluiten STR_1925 :Kan hier geen persoon plaatsen... STR_1926 :{SMALLFONT} @@ -1938,7 +1938,7 @@ STR_1936 :{STRINGID} heeft {STRINGID} gekocht STR_1937 :{SMALLFONT}{BLACK}Informatie tonen over het onderwerp van dit bericht STR_1938 :{SMALLFONT}{BLACK}Beeld van bezoeker tonen STR_1939 :{SMALLFONT}{BLACK}Beeld van werknemer tonen -STR_1940 :{SMALLFONT}{BLACK}Stemming, blijheid, hongerniveau e.d. van deze bezoeker tonen +STR_1940 :{SMALLFONT}{BLACK}Stemming, energie, hongerniveau e.d. van deze bezoeker tonen STR_1941 :{SMALLFONT}{BLACK}Tonen in welke attracties deze bezoeker is geweest STR_1942 :{SMALLFONT}{BLACK}Financiële informatie over deze bezoeker tonen STR_1943 :{SMALLFONT}{BLACK}Recente gedachten van deze bezoeker tonen @@ -2021,7 +2021,7 @@ STR_2019 :Actiefoto's STR_2020 :Paraplu's STR_2021 :Blikjes frisdrank STR_2022 :Hamburgers -STR_2023 :Zakjes fries +STR_2023 :Zakjes friet STR_2024 :IJsjes STR_2025 :Suikerspinnen STR_2026 :Lege blikjes @@ -2182,7 +2182,7 @@ STR_2180 :sujeonggwa STR_2181 :een broodje STR_2182 :een koekje STR_2183 :een lege kom -STR_2184 :een leeg drinkarton +STR_2184 :een leeg drinkpakje STR_2185 :een lege sapbeker STR_2186 :een gebraden worst STR_2187 :een lege kom @@ -2295,11 +2295,11 @@ STR_2293 :{BLACK} Geen STR_2294 :{SMALLFONT}{BLACK}Bovenkant land aanpassen STR_2295 :{SMALLFONT}{BLACK}Zijkant land aanpassen STR_2296 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} betaald voor entree -STR_2297 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} uitgeven aan {BLACK}{COMMA16} attractie +STR_2297 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} uitgegeven aan {BLACK}{COMMA16} attractie STR_2298 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} uitgegeven aan {BLACK}{COMMA16} attracties STR_2299 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} uitgegeven aan {BLACK}{COMMA16} stuk voedsel STR_2300 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} uitgegeven aan {BLACK}{COMMA16} stuks voedsel -STR_2301 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} uitgegeven aan {BLACK}{COMMA16} drankjr +STR_2301 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} uitgegeven aan {BLACK}{COMMA16} drankje STR_2302 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} uitgegeven aan {BLACK}{COMMA16} drankjes STR_2303 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} uitgegeven aan {BLACK}{COMMA16} souvenir STR_2304 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} uitgegeven aan {BLACK}{COMMA16} souvenirs @@ -2444,45 +2444,45 @@ STR_2442 :{BLACK}({STRINGID} resterend) STR_2443 :{WINDOW_COLOUR_2}Kosten per week: {BLACK}{CURRENCY2DP} STR_2444 :{WINDOW_COLOUR_2}Totale kosten: {BLACK}{CURRENCY2DP} STR_2445 :Start deze marketingcampagne -STR_2446 :{YELLOW}Je advertentiecampagne voor gratis entree tot het park is verlopen -STR_2447 :{YELLOW}Je advertentiecampagne voor gratis ritjes op {STRINGID} is verlopen -STR_2448 :{YELLOW}Je advertentiecampagne voor halve prijs entree tot het park is verlopen -STR_2449 :{YELLOW}Je advertentiecampagne voor gratis {STRINGID} is verlopen -STR_2450 :{YELLOW}Je advertentiecampagne voor het park is verlopen -STR_2451 :{YELLOW}Je advertentiecampagne voor {STRINGID} is verlopen +STR_2446 :{YELLOW}Je marketingcampagne voor gratis entree tot het park is afgelopen +STR_2447 :{YELLOW}Je marketingcampagne voor gratis ritjes op {STRINGID} is afgelopen +STR_2448 :{YELLOW}Je marketingcampagne voor 50% korting op de entree is afgelopen +STR_2449 :{YELLOW}Je marketingcampagne voor gratis {STRINGID} is afgelopen +STR_2450 :{YELLOW}Je advertentiecampagne voor het park is afgelopen +STR_2451 :{YELLOW}Je advertentiecampagne voor {STRINGID} is afgelopen STR_2452 :{WINDOW_COLOUR_2}Saldo (zonder lening): {BLACK}{CURRENCY2DP} STR_2453 :{WINDOW_COLOUR_2}Saldo (zonder lening): {RED}{CURRENCY2DP} STR_2454 :{SMALLFONT}{BLACK}{CURRENCY2DP} - STR_2455 :{SMALLFONT}{BLACK}+{CURRENCY2DP} - STR_2456 :{SMALLFONT}{BLACK}{CURRENCY2DP} - -STR_2457 :{SMALLFONT}{BLACK}Laat financiële rekeningen zien -STR_2458 :{SMALLFONT}{BLACK}Toon grafiek van geld (min lening) over tijd -STR_2459 :{SMALLFONT}{BLACK}Toon grafiek van parkwaarde over tijd +STR_2457 :{SMALLFONT}{BLACK}Laat financiële posten zien +STR_2458 :{SMALLFONT}{BLACK}Toon grafiek van saldoverloop (zonder lening) +STR_2459 :{SMALLFONT}{BLACK}Toon grafiek van parkwaardeverloop STR_2460 :{SMALLFONT}{BLACK}Toon grafiek van wekelijke winst -STR_2461 :{SMALLFONT}{BLACK}Toon advertentiecampagnes -STR_2462 :{SMALLFONT}{BLACK}Toon parkingang -STR_2463 :{SMALLFONT}{BLACK}Toon grafiek van parkwaardering over tijd -STR_2464 :{SMALLFONT}{BLACK}Toon grafiek van hoeveelheid gasten over tijd -STR_2465 :{SMALLFONT}{BLACK}Toon park entreeprijs en informatie -STR_2466 :{SMALLFONT}{BLACK}Toon park statistieken -STR_2467 :{SMALLFONT}{BLACK}Toon doelstellingen voor deze game +STR_2461 :{SMALLFONT}{BLACK}Toon marketingcampagnes +STR_2462 :{SMALLFONT}{BLACK}Toon beeld van de parkingang +STR_2463 :{SMALLFONT}{BLACK}Toon grafiek van parkwaarderingverloop +STR_2464 :{SMALLFONT}{BLACK}Toon grafiek met verloop van het aantal bezoekers +STR_2465 :{SMALLFONT}{BLACK}Toon de entreeprijs en -informatie +STR_2466 :{SMALLFONT}{BLACK}Toon parkstatistieken +STR_2467 :{SMALLFONT}{BLACK}Toon doelstellingen voor dit spel STR_2468 :{SMALLFONT}{BLACK}Toon recente prijzen die het park heeft gekregen -STR_2469 :{SMALLFONT}{BLACK}Selecteer niveau van onderzoek & ontwikkeling -STR_2470 :{SMALLFONT}{BLACK}Onderzoek nieuwe transportattracties -STR_2471 :{SMALLFONT}{BLACK}Onderzoek nieuwe rustige attracties -STR_2472 :{SMALLFONT}{BLACK}Onderzoek nieuwe achtbanen -STR_2473 :{SMALLFONT}{BLACK}Onderzoek nieuwe spannende attracties -STR_2474 :{SMALLFONT}{BLACK}Onderzoek nieuwe waterattracties -STR_2475 :{SMALLFONT}{BLACK}Onderzoek nieuwe winkels en kraampjes -STR_2476 :{SMALLFONT}{BLACK}Onderzoek nieuw decor en thematisering -STR_2477 :{SMALLFONT}{BLACK}Selecteer werkzame modus voor deze attractie -STR_2478 :{SMALLFONT}{BLACK}Toon grafiek van snelheid over tijd -STR_2479 :{SMALLFONT}{BLACK}Toon grafiek van hoogte over tijd -STR_2480 :{SMALLFONT}{BLACK}Toon grafiek van verticale versnelling over tijd -STR_2481 :{SMALLFONT}{BLACK}Toon grafiek van horizontale versnelling over tijd -STR_2482 :{SMALLFONT}{BLACK}Winst: {CURRENCY} per week, Parkwaarde: {CURRENCY} -STR_2483 :{WINDOW_COLOUR_2}Wekelijke winst: {BLACK}+{CURRENCY2DP} -STR_2484 :{WINDOW_COLOUR_2}Wekelijke winst: {RED}{CURRENCY2DP} +STR_2469 :{SMALLFONT}{BLACK}Selecteer niveau van onderzoek en ontwikkeling +STR_2470 :{SMALLFONT}{BLACK}Onderzoek naar nieuwe transportattracties +STR_2471 :{SMALLFONT}{BLACK}Onderzoek naar nieuwe rustige attracties +STR_2472 :{SMALLFONT}{BLACK}Onderzoek naar nieuwe achtbanen +STR_2473 :{SMALLFONT}{BLACK}Onderzoek naar nieuwe spannende attracties +STR_2474 :{SMALLFONT}{BLACK}Onderzoek naar nieuwe waterattracties +STR_2475 :{SMALLFONT}{BLACK}Onderzoek naar nieuwe winkels en kraampjes +STR_2476 :{SMALLFONT}{BLACK}Onderzoek naar nieuw decor en nieuwe thema's +STR_2477 :{SMALLFONT}{BLACK}Selecteer werkmodus voor deze attractie +STR_2478 :{SMALLFONT}{BLACK}Toon grafiek van snelheidsverloop +STR_2479 :{SMALLFONT}{BLACK}Toon grafiek van hoogteverloop +STR_2480 :{SMALLFONT}{BLACK}Toon grafiek met verloop van verticale versnelling +STR_2481 :{SMALLFONT}{BLACK}Toon grafiek met verloop van zijwaartse versnelling +STR_2482 :{SMALLFONT}{BLACK}Winst: {CURRENCY} per week, parkwaarde: {CURRENCY} +STR_2483 :{WINDOW_COLOUR_2}Wekelijkse winst: {BLACK}+{CURRENCY2DP} +STR_2484 :{WINDOW_COLOUR_2}Wekelijkse winst: {RED}{CURRENCY2DP} STR_2485 :Besturing STR_2486 :Algemeen STR_2487 :'Echte' namen van bezoekers tonen @@ -2490,37 +2490,37 @@ STR_2488 :{SMALLFONT}{BLACK}Wissel tussen het tonen van 'echte' namen van bez STR_2489 :Sneltoetsen... STR_2490 :Sneltoetsen STR_2491 :Toetsen herstellen -STR_2492 :{SMALLFONT}{BLACK}Herstel alle toetsen terug naar de standaard instellingen -STR_2493 :Close top-most window -STR_2494 :Close all floating windows -STR_2495 :Cancel construction mode +STR_2492 :{SMALLFONT}{BLACK}Alle sneltoetsen terugzetten op de standaardinstellingen +STR_2493 :Sluit bovenste venster +STR_2494 :Sluit alle openstaande vensters +STR_2495 :Bouwmodus annuleren STR_2496 :Spel pauzeren -STR_2497 :Zoom aanblik uit -STR_2498 :Zoom aanblik in -STR_2499 :Draai aanblik -STR_2500 :Draai constructieobject -STR_2501 :Onder de grond kijken -STR_2502 :Verwijder basis land -STR_2503 :Verwijder verticaal land +STR_2497 :Beeld uitzoomen +STR_2498 :Beeld inzoomen +STR_2499 :Beeld draaien +STR_2500 :Object draaien +STR_2501 :Ondergrondszicht +STR_2502 :Bovenkant land onzichtbaar +STR_2503 :Zijkant land onzichtbaar STR_2504 :Doorzichtige attracties STR_2505 :Doorzichtig decor -STR_2506 :Onzichtbare ondersteuning +STR_2506 :Onzichtbare ondersteuningen STR_2507 :Onzichtbare bezoekers STR_2508 :Toon hoogtemarkeringen op land -STR_2509 :Toon hoogtemarkeringen op rails +STR_2509 :Toon hoogtemarkeringen op attracties STR_2510 :Toon hoogtemarkeringen op paden STR_2511 :Land aanpassen STR_2512 :Water aanpassen STR_2513 :Decor bouwen -STR_2514 :Bouw paden -STR_2515 :Bouw nieuwe attractie -STR_2516 :Toon financiële informatie -STR_2517 :Toon onderzoeksinformatie -STR_2518 :Toon lijst met attracties -STR_2519 :Toon park informatie -STR_2520 :Toon lijst met bezoekers -STR_2521 :Toon lijst met werknemers -STR_2522 :Toon recente berichten +STR_2514 :Voetpaden bouwen +STR_2515 :Nieuwe attractie bouwen +STR_2516 :Financiële informatie tonen +STR_2517 :Onderzoeksinformatie tonen +STR_2518 :Lijst met attracties tonen +STR_2519 :Parkinformatie tonen +STR_2520 :Lijst met bezoekers tonen +STR_2521 :Lijst met werknemers tonen +STR_2522 :Recente berichten tonen STR_2523 :Kaart tonen STR_2524 :Screenshot STR_2525 :??? @@ -2536,7 +2536,7 @@ STR_2534 :Tab STR_2535 :??? STR_2536 :??? STR_2537 :Wissen -STR_2538 :Enter +STR_2538 :Return STR_2539 :??? STR_2540 :??? STR_2541 :??? @@ -2784,7 +2784,7 @@ STR_2782 :SHIFT + STR_2783 :CTRL + STR_2784 :Sneltoets wijzigen STR_2785 :{WINDOW_COLOUR_2}Voer een nieuwe sneltoets in voor:{NEWLINE}{OPENQUOTES}{STRINGID}{ENDQUOTES} -STR_2786 :{SMALLFONT}{BLACK}Click on shortcut description to select new key +STR_2786 :{SMALLFONT}{BLACK}Klik op de beschrijving op een nieuwe sneltoets in te stellen STR_2787 :{WINDOW_COLOUR_2}Parkwaarde: {BLACK}{CURRENCY} STR_2788 :{WINDOW_COLOUR_2}Gefeliciteerd!{NEWLINE}{BLACK}Je hebt je doel bereikt met een bedrijfswaarde van {CURRENCY}! STR_2789 :{WINDOW_COLOUR_2}Je hebt je doel niet bereikt! @@ -2796,7 +2796,7 @@ STR_2794 :{WINDOW_COLOUR_2}Voltooid door: {BLACK}{STRINGID}{NEWLINE}{WINDOW_C STR_2795 :Sorteren STR_2796 :{SMALLFONT}{BLACK}Sorteer de lijst met attracties op basis van het aangegeven informatietype STR_2797 :Beeld verschuiven als aanwijzer op de rand staat -STR_2798 :{SMALLFONT}{BLACK}Selecteer of het beeld wel of niet moet verschuiven als de muisaanwijzer op de rand van het beeld staat +STR_2798 :{SMALLFONT}{BLACK}Selecteer of het beeld moet verschuiven als de muisaanwijzer op de rand van het beeld staat STR_2799 :{SMALLFONT}{BLACK}Instellingen voor sneltoetsen bekijken of aanpassen STR_2800 :{WINDOW_COLOUR_2}Totale bezoeken: {BLACK}{COMMA32} STR_2801 :{WINDOW_COLOUR_2}Entree-inkomsten: {BLACK}{CURRENCY2DP} @@ -2804,14 +2804,14 @@ STR_2802 :Kaart STR_2803 :{SMALLFONT}{BLACK}Parkkaart tonen waarop deze bezoekers gemarkeerd zijn STR_2804 :{SMALLFONT}{BLACK}Parkkaart tonen waarop deze werknemers gemarkeerd zijn STR_2805 :{SMALLFONT}{BLACK}Parkkaart tonen -STR_2806 :{RED}Guests are complaining about the disgusting state of the paths in your park{NEWLINE}Check where your handymen are and consider organizing them better -STR_2807 :{RED}Guests are complaining about the amount of litter in your park{NEWLINE}Check where your handymen are and consider organizing them better -STR_2808 :{RED}Guests are complaining about the vandalism in your park{NEWLINE}Check where your security guards are and consider organizing them better -STR_2809 :{RED}Guests are hungry and can't find anywhere to buy food -STR_2810 :{RED}Guests are thirsty and can't find anywhere to buy drinks -STR_2811 :{RED}Guests are complaining because they can't find the restrooms in your park -STR_2812 :{RED}Guests are getting lost or stuck{NEWLINE}Check whether the layout of your footpaths needs improving to help the guests find their way around -STR_2813 :{RED}Your park entrance fee is too Hoog!{NEWLINE}Reduce your entrance fee or improve the value of the park to attract more guests +STR_2806 :{RED}Bezoekers klagen over de smerige voetpaden in je park{NEWLINE}Controleer waar je klusjesmannen zijn en overweeg om ze beter te organiseren +STR_2807 :{RED}Bezoekers klagen over de hoeveelheid rommel{NEWLINE}Controleer waar je klusjesmannen zijn en overweeg om ze beter te organiseren +STR_2808 :{RED}Bezoekers klagen over het vandalisme in je park{NEWLINE}Controleer waar je bewakers zijn en overweeg om ze beter te organiseren +STR_2809 :{RED}Bezoekers hebben honger en kunnen geen plek vinden om voedsel te kopen +STR_2810 :{RED}Bezoekers hebben dorst en kunnen geen plek vinden om drinken te kopen +STR_2811 :{RED}Bezoekers klagen omdat ze de toiletten in je park niet kunnen vinden +STR_2812 :{RED}Bezoekers raken verdwaald of komen vast te zitten{NEWLINE}Controleer of de indeling van je voetpaden voor verbetering vatbaar is +STR_2813 :{RED}Je entreeprijs is te hoog!{NEWLINE}Verlaag de entreeprijs of verbeter het park om meer bezoekers te trekken STR_2814 :{WINDOW_COLOUR_2}Rommeligste park STR_2815 :{WINDOW_COLOUR_2}Netste park STR_2816 :{WINDOW_COLOUR_2}Beste achtbanen @@ -2819,7 +2819,7 @@ STR_2817 :{WINDOW_COLOUR_2}Beste park STR_2818 :{WINDOW_COLOUR_2}Mooiste park STR_2819 :{WINDOW_COLOUR_2}Slechtste park STR_2820 :{WINDOW_COLOUR_2}Veiligste park -STR_2821 :{WINDOW_COLOUR_2}Beste werknemers +STR_2821 :{WINDOW_COLOUR_2}Beste personeel STR_2822 :{WINDOW_COLOUR_2}Beste eten STR_2823 :{WINDOW_COLOUR_2}Slechtste eten STR_2824 :{WINDOW_COLOUR_2}Beste toiletten @@ -2829,39 +2829,39 @@ STR_2827 :{WINDOW_COLOUR_2}Beste unieke attracties STR_2828 :{WINDOW_COLOUR_2}Meest duizelingwekkende kleurenschema STR_2829 :{WINDOW_COLOUR_2}Vreemdste indeling STR_2830 :{WINDOW_COLOUR_2}Beste rustige attracties -STR_2831 :{TOPAZ}Je park heeft een prijs gekregen voor 'Het rommeligste park in het land zijn' -STR_2832 :{TOPAZ}Je park heeft een prijs gekregen voor 'Het netste park in het land zijn' -STR_2833 :{TOPAZ}Je park heeft een prijs gekregen voor 'Het park met de beste achtbanen in het land zijn' -STR_2834 :{TOPAZ}Je park heeft een prijs gekregen voor 'Het beste park in het land zijn' -STR_2835 :{TOPAZ}Je park heeft een prijs gekregen voor 'Het mooiste park in het land zijn' -STR_2836 :{TOPAZ}Je park heeft een prijs gekregen voor 'Het slechtste park in het land zijn' -STR_2837 :{TOPAZ}Je park heeft een prijs gekregen voor 'Het veiligste park in het land zijn' -STR_2838 :{TOPAZ}Je park heeft een prijs gekregen voor 'Het park met de beste werknemers in het land zijn' -STR_2839 :{TOPAZ}Je park heeft een prijs gekregen voor 'Het park met het beste eten in het land zijn' -STR_2840 :{TOPAZ}Je park heeft een prijs gekregen voor 'Het park met het slechtste eten in het land zijn' -STR_2841 :{TOPAZ}Je park heeft een prijs gekregen voor 'Het park met de beste toiletten in het land zijn' -STR_2842 :{TOPAZ}Je park heeft een prijs gekregen voor 'Het meest teleurstellende park in het land zijn' -STR_2843 :{TOPAZ}Je park heeft een prijs gekregen voor 'Het park met de beste waterattracties in het land zijn' -STR_2844 :{TOPAZ}Je park heeft een prijs gekregen voor 'Het park met de beste unieke attracties in het land zijn' -STR_2845 :{TOPAZ}Je park heeft een prijs gekregen voor 'Het park met de meest duizelingwekkende kleurenschemas in het land zijn' -STR_2846 :{TOPAZ}Je park heeft een prijs gekregen voor 'Het park met de vreemste indeling in het land zijn' -STR_2847 :{TOPAZ}Je park heeft een prijs gekregen voor 'Het park met de beste rustige attracties in het land zijn' +STR_2831 :{TOPAZ}Je park heeft een prijs gekregen: 'Rommeligste park van het land'! +STR_2832 :{TOPAZ}Je park heeft een prijs gekregen: 'Netste park van het land'! +STR_2833 :{TOPAZ}Je park heeft een prijs gekregen: 'Park met de beste achtbanen'! +STR_2834 :{TOPAZ}Je park heeft een prijs gekregen: 'Beste park van het land'! +STR_2835 :{TOPAZ}Je park heeft een prijs gekregen: 'Mooiste park van het land'! +STR_2836 :{TOPAZ}Je park heeft een prijs gekregen: 'Slechtste park van het land'! +STR_2837 :{TOPAZ}Je park heeft een prijs gekregen: 'Veiligste park'! +STR_2838 :{TOPAZ}Je park heeft een prijs gekregen: 'Park met de beste werknemers'! +STR_2839 :{TOPAZ}Je park heeft een prijs gekregen: 'Park met het beste eten van het land'! +STR_2840 :{TOPAZ}Je park heeft een prijs gekregen: 'Park met het slechtste eten van het land'! +STR_2841 :{TOPAZ}Je park heeft een prijs gekregen: 'Park met de beste toiletten van het land'! +STR_2842 :{TOPAZ}Je park heeft een prijs gekregen: 'Meest teleurstellende park'! +STR_2843 :{TOPAZ}Je park heeft een prijs gekregen: 'Park met de beste waterattracties'! +STR_2844 :{TOPAZ}Je park heeft een prijs gekregen: 'Park met de beste unieke attracties'! +STR_2845 :{TOPAZ}Je park heeft een prijs gekregen: 'Park met het meest duizelingwekkende kleurenschema'! +STR_2846 :{TOPAZ}Je park heeft een prijs gekregen: 'Park met de vreemdste indeling'! +STR_2847 :{TOPAZ}Je park heeft een prijs gekregen: 'Park met de beste rustige attracties'! STR_2848 :{WINDOW_COLOUR_2}Geen recente prijzen -STR_2849 :Nieuw scenario successvol geïnstalleerd -STR_2850 :Nieuw baanontwerp successvol geïnstalleerd -STR_2851 :Scenario al geïnstalleerd -STR_2852 :Baanontwerp al geïnstalleerd -STR_2853 :Verboden door de lokale overheid! -STR_2854 :{RED}Bezoekers kunnen niet bij de ingang van {STRINGID} komen!{NEWLINE}Maak een pad naar de ingang -STR_2855 :{RED}{STRINGID} heeft geen pad vanaf zijn uitgang !{NEWLINE}Maak een pad vanaf de uitgang -STR_2856 :{WINDOW_COLOUR_2}Snelcursus -STR_2857 :{WINDOW_COLOUR_2}(Press a key or mouse button to take control) -STR_2858 :Kan advertentiecampagne niet starten... -STR_2859 :Een andere instantie van RollerCoaster Tycoon 2 draait al -STR_2860 :Infogrames Interactive credits... -STR_2861 :{WINDOW_COLOUR_2}Licensed to Infogrames Interactive Inc. -STR_2862 :Music acknowledgements... -STR_2863 :Music acknowledgements +STR_2849 :Nieuw scenario is succesvol geïnstalleerd +STR_2850 :Nieuw baanontwerp is succesvol geïnstalleerd +STR_2851 :Scenario al is geïnstalleerd +STR_2852 :Baanontwerp is al geïnstalleerd +STR_2853 :Niet toegestaan door de gemeente! +STR_2854 :{RED}Bezoekers kunnen niet bij de ingang van {STRINGID} komen!{NEWLINE}Bouw een pad naar de ingang +STR_2855 :{RED}{STRINGID} heeft geen pad vanaf de uitgang!{NEWLINE}Bouw een pad vanaf de uitgang +STR_2856 :{WINDOW_COLOUR_2}Tutorial +STR_2857 :{WINDOW_COLOUR_2}(Druk op een toets of muisknop om de controle over te nemen) +STR_2858 :Kan marketingcampagne niet starten... +STR_2859 :RollerCoaster Tycoon 2 draait al +STR_2860 :Credits voor Infogrames Interactive... +STR_2861 :{WINDOW_COLOUR_2}In licentie geven aan Infogrames Interactive Inc. +STR_2862 :Muziekdankwoord... +STR_2863 :Muziekdankwoord STR_2864 :{WINDOW_COLOUR_2}March - Children of the Regiment: (Fucik) geen copyright STR_2865 :{WINDOW_COLOUR_2}Heyken's Serenade: (J.Heyken) British Standard Music Coy; GEMA, BRITICO STR_2866 :{WINDOW_COLOUR_2}In Continental Mood: (Onbekende componist) Copyright Control @@ -2967,7 +2967,7 @@ STR_2965 :{WINDOW_COLOUR_2} STR_2966 : STR_2967 : STR_2968 : -STR_2969 :Het gebruik van dit product is onderhevig aan de bepalen in de gebruikersovereenkomst +STR_2969 :Het gebruik van dit product is onderhevig aan de bepalingen in de gebruikersovereenkomst STR_2970 :die te raadplegen is in de {OPENQUOTES}ReadMe{ENDQUOTES} of de handleiding. STR_2971 :Standaard kleurenschema STR_2972 :Alternatief kleurenschema 1 @@ -2984,11 +2984,11 @@ STR_2982 :Baniertekst STR_2983 :Voer een nieuwe tekst in voer deze banier: STR_2984 :Kan de tekst op deze banier niet veranderen... STR_2985 :Banier -STR_2986 :{SMALLFONT}{BLACK}Change text on banner -STR_2987 :{SMALLFONT}{BLACK}Set this banner as a 'no-entry' sign for guests -STR_2988 :{SMALLFONT}{BLACK}Demolish this banner -STR_2989 :{SMALLFONT}{BLACK}Select main color -STR_2990 :{SMALLFONT}{BLACK}Select text color +STR_2986 :{SMALLFONT}{BLACK}Tekst op deze banier aanpassen +STR_2987 :{SMALLFONT}{BLACK}Deze banier gebruiken als bord voor 'geen toegang' voor de bezoekers +STR_2988 :{SMALLFONT}{BLACK}Deze banier vernietigen +STR_2989 :{SMALLFONT}{BLACK}Hoofdkleur selecteren +STR_2990 :{SMALLFONT}{BLACK}Tekstkleur selecteren STR_2991 :Bord STR_2992 :Bordtekst STR_2993 :Voer een nieuwe tekst in voor dit bord: @@ -3010,43 +3010,43 @@ STR_3008 :{PEARLAQUA}ABC STR_3009 :{PALESILVER}ABC STR_3010 :Kan dit bestand niet laden... STR_3011 :Bestand bevat ongeldige gegevens -STR_3012 :Botsautos beat stijl +STR_3012 :Botsautostijl STR_3013 :Kermisorgelstijl -STR_3014 :Romijnse fanfare stijl -STR_3015 :Orientaalse stijl -STR_3016 :Marsmannetjes stijl -STR_3017 :Jungle drums stijl +STR_3014 :Romeinsefanfarestijl +STR_3015 :Oosterse stijl +STR_3016 :Marsstijl +STR_3017 :Jungledrumsstijl STR_3018 :Egyptische stijl -STR_3019 :Speelgoedland stijl +STR_3019 :Speelgoedlandstijl STR_3020 : -STR_3021 :Ruimte stijl -STR_3022 :Horror stijl -STR_3023 :Techno stijl +STR_3021 :Ruimtestijl +STR_3022 :Horrorstijl +STR_3023 :Technostijl STR_3024 :Rustige stijl STR_3025 :Zomerstijl -STR_3026 :Water stijl -STR_3027 :Wilde westen stijl -STR_3028 :Jurassic stijl -STR_3029 :Rock stijl -STR_3030 :Ragtime stijl -STR_3031 :Fantasy stijl -STR_3032 :Rock stijl 2 -STR_3033 :Ijs stijl -STR_3034 :Sneeuw stijl +STR_3026 :Waterstijl +STR_3027 :Wildweststijl +STR_3028 :Jurastijl +STR_3029 :Rockstijl +STR_3030 :Ragtimestijl +STR_3031 :Fantasiestijl +STR_3032 :Rockstijl 2 +STR_3033 :IJsstijl +STR_3034 :Sneeuwstijl STR_3035 :Extra muziek 1 STR_3036 :Extra muziek 2 STR_3037 :Middeleeuwse stijl -STR_3038 :Stedelijke stijl -STR_3039 :Orgel stijl +STR_3038 :Stadsstijl +STR_3039 :Orgelstijl STR_3040 :Mechanische stijl STR_3041 :Moderne stijl -STR_3042 :Piraten stijl -STR_3043 :Rock stijl 3 -STR_3044 :Snoepjes stijl -STR_3045 :{SMALLFONT}{BLACK}Selecteer muziekstijl om te spelen +STR_3042 :Piratenstijl +STR_3043 :Rockstijl 3 +STR_3044 :Snoepstijl +STR_3045 :{SMALLFONT}{BLACK}Selecteer welke muziekstijl er moet worden gespeeld STR_3046 :Deze attractie kan niet worden aangepast -STR_3047 :Lokale overheid verbied sloop of verandering van deze attractie -STR_3048 :Advertentiecampagnes verboden door lokale overheid +STR_3047 :De gemeente staat de sloop van en wijzigingen aan deze attractie niet toe +STR_3048 :Marketingcampagnes worden niet toegestaan door de gemeente STR_3049 :Golfhole A STR_3050 :Golfhole B STR_3051 :Golfhole C @@ -3070,11 +3070,11 @@ STR_3068 :Andere parken STR_3069 :Bovensegment STR_3070 :Van helling naar vlak STR_3071 :{WINDOW_COLOUR_2}Dezelfde prijs in het hele park -STR_3072 :{SMALLFONT}{BLACK}Selecteer of dezelfde prijs word gebruikt door het hele park -STR_3073 :{RED}WAARSCHUWING: Je parkwaardering is onder 700 gezakt!{NEWLINE}Als je je parkwaardering niet verhoogd binnen 4 weken word je park gesloten -STR_3074 :{RED}WAARSCHUWING: Je parkwaardering is nog steeds onder 700 !{NEWLINE}Je hebt 3 weken om je waardering te verhogen -STR_3075 :{RED}WAARSCHUWING: Je parkwaardering is nog steeds onder 700 !{NEWLINE}Je hebt nog maar 2 weken om je waardering te verhogen, of je park word gesloten -STR_3076 :{RED}LAATSTE WAARSCHUWING: Je parkwaardering is nog steeds onder 700 !{NEWLINE}Over 7 dagen word je park gesloten als je je waardering niet verhoogd +STR_3072 :{SMALLFONT}{BLACK}Selecteer of deze prijs in het hele park moet worden gehanteerd +STR_3073 :{RED}WAARSCHUWING: Je parkwaardering is onder de 700 gekomen!{NEWLINE}Als je niet binnen 4 weken de waardering boven de 700 hebt gekregen, wordt je park gesloten +STR_3074 :{RED}WAARSCHUWING: Je parkwaardering is nog steeds lager dan 700!{NEWLINE}Je hebt nog 3 weken om de waardering te verhogen +STR_3075 :{RED}WAARSCHUWING: Je parkwaardering is nog steeds lager dan 700!{NEWLINE}Je hebt nog maar 2 weken om de waardering te verhogen, anders wordt je park gesloten +STR_3076 :{RED}LAATSTE WAARSCHUWING: Je parkwaardering is nog steeds lager dan 700!{NEWLINE}Je hebt nog maar 7 dagen om die te verhogen, anders wordt je park gesloten STR_3077 :{RED}SLUITINGSBERICHT: Je park is gesloten! STR_3078 :Standaardingang STR_3079 :Houten ingang @@ -3088,20 +3088,20 @@ STR_3086 :Abstracte ingang STR_3087 :Sneeuw/ijs-ingang STR_3088 :Pagode-ingang STR_3089 :Ruimte-ingang -STR_3090 :{SMALLFONT}{BLACK}Selecteer stijl van de ingang, uitgang, en het station +STR_3090 :{SMALLFONT}{BLACK}Selecteer de stijl van de ingang, uitgang, en het station STR_3091 :Je mag dit segment niet verwijderen! STR_3092 :Je mag het station van deze attractie niet verplaatsen of veranderen! STR_3093 :{WINDOW_COLOUR_2}Favoriet: {BLACK}{STRINGID} STR_3094 :n.v.t. -STR_3095 :{WINDOW_COLOUR_2}Lift helling snelheid: +STR_3095 :{WINDOW_COLOUR_2}Snelheid kettingheuvel: STR_3096 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{VELOCITY} -STR_3097 :{SMALLFONT}{BLACK}Selecteer lift helling ketting snelheid -STR_3098 :Kan lift helling snelheid niet veranderen... -STR_3099 :{SMALLFONT}{BLACK}Selecteer kleur -STR_3100 :{SMALLFONT}{BLACK}Selecteer kleur twee -STR_3101 :{SMALLFONT}{BLACK}Selecteer kleur drie -STR_3102 :{SMALLFONT}{BLACK}Re-paint colored scenery on landscape??? -STR_3103 :Can't re-paint this... +STR_3097 :{SMALLFONT}{BLACK}Selecteer de snelheid van de kettingheuvel +STR_3098 :Kan de snelheid van de kettingheuvel niet veranderen... +STR_3099 :{SMALLFONT}{BLACK}Kleur selecteren +STR_3100 :{SMALLFONT}{BLACK}Tweede kleur selecteren +STR_3101 :{SMALLFONT}{BLACK}Derde kleur selecteren +STR_3102 :{SMALLFONT}{BLACK}Gekleurd decor opnieuw verven +STR_3103 :Kan dit niet opnieuw ververen... STR_3104 :{SMALLFONT}{BLACK}Toon een lijst van attracties STR_3105 :{SMALLFONT}{BLACK}Toon een lijst van winkels en kraampjes STR_3106 :{SMALLFONT}{BLACK}Toon een lijst van informatiekiosken en andere faciliteiten @@ -3109,37 +3109,37 @@ STR_3107 :Sluiten STR_3108 :Testen STR_3109 :Openen STR_3110 :{WINDOW_COLOUR_2}Blokken: {BLACK}{COMMA16} -STR_3111 :{SMALLFONT}{BLACK}Klik op ontwerp om het te bouwen -STR_3112 :{SMALLFONT}{BLACK}Klik op ontwerp om het te verwijderen of om het een andere naam te geven -STR_3113 :Selecteer een ander ontwerp -STR_3114 :{SMALLFONT}{BLACK}Ga terug naar ontwerp keuzevenster -STR_3115 :{SMALLFONT}{BLACK}Sla baanontwerp op -STR_3116 :{SMALLFONT}{BLACK}Sla baanontwerp op (Niet mogelijk totdat de attractie getest is en statestieken bepaald zijn) -STR_3117 :{BLACK}Monteur bellen... -STR_3118 :{BLACK}{STRINGID} gaat naar de attractie -STR_3119 :{BLACK}{STRINGID} is de attractie aan het repareren -STR_3120 :{SMALLFONT}{BLACK}Vind dichstbijzijnde monteur, of monteur die de attractie aan het repareren is -STR_3121 :Kan monteur niet vinden, of alle monteurs zijn bezig -STR_3122 :{WINDOW_COLOUR_2}Favoriete attractie van: {BLACK}{COMMA16} bezoeker -STR_3123 :{WINDOW_COLOUR_2}Favoriete attractie van: {BLACK}{COMMA16} bezoekers +STR_3111 :{SMALLFONT}{BLACK}Klik op het ontwerp om het te bouwen +STR_3112 :{SMALLFONT}{BLACK}Klik op het ontwerp om het te verwijderen of om het een andere naam te geven +STR_3113 :Een ander ontwerp selecteren +STR_3114 :{SMALLFONT}{BLACK}Terug naar ontwerpselectie +STR_3115 :{SMALLFONT}{BLACK}Baanontwerp opslaan +STR_3116 :{SMALLFONT}{BLACK}Baanontwerp opslaan (Niet mogelijk voordat de attractie is getest en de statistieken zijn gegenereerd) +STR_3117 :{BLACK}Monteur wordt opgeroepen... +STR_3118 :{BLACK}{STRINGID} gaat naar deze attractie +STR_3119 :{BLACK}{STRINGID} is bezig deze attractie te repareren +STR_3120 :{SMALLFONT}{BLACK}Vind de dichtstbijzijnde monteur, of de monteur die de attractie aan het repareren is +STR_3121 :Kan geen monteur vinden, of alle monteurs in de buurt zijn bezig +STR_3122 :{WINDOW_COLOUR_2}Favoriet van: {BLACK}{COMMA16} bezoeker +STR_3123 :{WINDOW_COLOUR_2}Favoriet van: {BLACK}{COMMA16} bezoekers STR_3124 :{STRINGID} defect -STR_3125 :{WINDOW_COLOUR_2}Opwinding: {BLACK}+{COMMA16}% -STR_3126 :{WINDOW_COLOUR_2}Intensiteit: {BLACK}+{COMMA16}% -STR_3127 :{WINDOW_COLOUR_2}Misselijkmakendheid: {BLACK}+{COMMA16}% +STR_3125 :{WINDOW_COLOUR_2}Spanningsfactor: {BLACK}+{COMMA16}% +STR_3126 :{WINDOW_COLOUR_2}Intensiteitsfactor: {BLACK}+{COMMA16}% +STR_3127 :{WINDOW_COLOUR_2}Misselijkheidsfactor: {BLACK}+{COMMA16}% STR_3128 :Baanontwerp opslaan STR_3129 :Baanontwerp en decor opslaan STR_3130 :Opslaan STR_3131 :Annuleren -STR_3132 :{BLACK}Klik op decoritems om ze op te laten slaan met het baanontwerp... +STR_3132 :{BLACK}Klik op decoritems om ze op te slaan met het baanontwerp... STR_3133 :Kan dit niet bouwen op een helling -STR_3134 :{RED}(Ontwerp bezit decor dat niet beschikbaar is) -STR_3135 :{RED}(Karretjestype niet beschikbaar - baanprestatie kan beïnvloed worden) -STR_3136 :Waarschuwing: Dit ontwerp word gebouwd met een ander type karretje, en kan onverwachte prestaties leveren +STR_3134 :{RED}(Ontwerp bevat decor dat niet beschikbaar is) +STR_3135 :{RED}(Karretjestype niet beschikbaar - dit kan van invloed zijn op de baanprestaties) +STR_3136 :Waarschuwing: Dit ontwerp zal worden gebouwd met een ander type karretje, wat onverwachte effecten met zich mee kan brengen STR_3137 :Decor naast baan selecteren STR_3138 :Alles deselecteren -STR_3139 :Stoeltjeslift kan niet werken in deze operatiemodus -STR_3140 :Stoeltjeslift moet meteen beginnen na station -STR_3141 :Meerdere rondjes per rit niet mogelijk met een stoeltjeslift +STR_3139 :Kabellift kan niet functioneren in deze werkmodus +STR_3140 :Kabellift moet meteen na het station beginnen +STR_3141 :Meerdere circuits zijn niet mogelijk met een kabellift STR_3142 :{WINDOW_COLOUR_2}Capaciteit: {BLACK}{STRINGID} STR_3143 :{SMALLFONT}{BLACK}Laat bezoekers zien op kaart STR_3144 :{SMALLFONT}{BLACK}Laat attracties en kraampjes zien op kaart @@ -3172,72 +3172,72 @@ STR_3170 :Niet genoeg ruimte voor graphics STR_3171 :Te veel objecten van dit type geselecteerd STR_3172 :De volgende objecten moeten eerst geselecteerd worden: STR_3173 :Dit object is momenteel in gebruik -STR_3174 :Dit object word benodigd door een ander object +STR_3174 :Een ander object is afhankelijk van dit object STR_3175 :Dit object is altijd benodigd STR_3176 :Kan object niet selecteren -STR_3177 :Kan object niet de-selecteren -STR_3178 :Tenminste 1 padobject moet geselecteerd zijn -STR_3179 :Tenminste 1 attractie moet geselecteerd zijn +STR_3177 :Kan object niet deselecteren +STR_3178 :Er moet minstens één voetpad worden geselecteerd +STR_3179 :Er moet minstens één attractie worden geselecteerd STR_3180 :Ongeldige selectie van objecten -STR_3181 :Object Selectie - {STRINGID} -STR_3182 :Park ingang moet geselecteerd zijn -STR_3183 :Water type moet geselecteerd zijn -STR_3184 :Attracties -STR_3185 :Klein Decor -STR_3186 :Groot Decor -STR_3187 :Muren/Hekjes -STR_3188 :Pad Borden +STR_3181 :Objectselectie - {STRINGID} +STR_3182 :Er moet een parkingang worden geselecteerd +STR_3183 :Er moet een watertyoe worden geselecteerd +STR_3184 :Attracties/voertuigen +STR_3185 :Klein decor +STR_3186 :Groot decor +STR_3187 :Muren/hekken +STR_3188 :Borden voor paden STR_3189 :Voetpaden -STR_3190 :Pad Extras -STR_3191 :Decor Groepen -STR_3192 :Park Ingang +STR_3190 :Extra's voor paden +STR_3191 :Decorgroepen +STR_3192 :Parkingang STR_3193 :Water -STR_3194 :Scenario Beschrijving -STR_3195 :Uitvindingen Lijst +STR_3194 :Scenariobeschrijving +STR_3195 :Lijst van uitvindingen STR_3196 :{WINDOW_COLOUR_2}Onderzoeksgroep: {BLACK}{STRINGID} -STR_3197 :{WINDOW_COLOUR_2}Items onderzocht aan begin van het spel: -STR_3198 :{WINDOW_COLOUR_2}Items die onderzocht worden tijdens het spel: -STR_3199 :Willekeurig -STR_3200 :{SMALLFONT}{BLACK}Schuffle de lijst met items die onderzocht moeten worden tijdens het spel -STR_3201 :Object Selectie -STR_3202 :Landschap Aanpassen -STR_3203 :Uitvindingen Lijst Opgezet -STR_3204 :Opties Selectie -STR_3205 :Objective Selectie -STR_3206 :Sla Scenario Op -STR_3207 :Achtbaan Ontwerper -STR_3208 :Baan Ontwerp Manager -STR_3209 :Terug Naar Vorige Stap: -STR_3210 :Door Naar Volgende Stap: -STR_3211 :{WINDOW_COLOUR_2}Kaart grootte:up +STR_3197 :{WINDOW_COLOUR_2}Items die aan het begin al zijn uitgevonden: +STR_3198 :{WINDOW_COLOUR_2}Items die tijdens het spel kunnen worden uitgevonden: +STR_3199 :Willekeurige volgorde +STR_3200 :{SMALLFONT}{BLACK}Zet de lijst van tijdens het spel uit te vinden items in een willekeurige volgorde +STR_3201 :Objectselectie +STR_3202 :Landschap bewerken +STR_3203 :Uitvindingen instellen +STR_3204 :Opties selecteren +STR_3205 :Doel selecteren +STR_3206 :Scenario opslaan +STR_3207 :Achtbaanontwerper +STR_3208 :Baanontwerpbeheer +STR_3209 :Terug naar de vorige stap: +STR_3210 :Verder naar de volgende stap: +STR_3211 :{WINDOW_COLOUR_2}Kaartgrootte: STR_3212 :{POP16}{COMMA16} x {PUSH16}{COMMA16} STR_3213 :Kan kaart niet verder verkleinen STR_3214 :Kan kaart niet verder vergroten -STR_3215 :Te dicht bij rand van de kaart -STR_3216 :{SMALLFONT}{BLACK}Selecteer parkland etc. -STR_3217 :Parkland -STR_3218 :Land Met Constructierechten -STR_3219 :Land Te Koop -STR_3220 :Constructierechten Te Koop -STR_3221 :{SMALLFONT}{BLACK}Geef aan welk land van het park is -STR_3222 :{SMALLFONT}{BLACK}Geef aan van welk land het park constructierechten heeft -STR_3223 :{SMALLFONT}{BLACK}Geef aan welk land gekocht kan worden door het park -STR_3224 :{SMALLFONT}{BLACK}Geef aan welk land constructierechten heeft die te koop zijn -STR_3225 :{SMALLFONT}{BLACK}Wissel aan/uit van het bouwen van een willekeurige cluster van objecten rondom de geselecteerde positie -STR_3226 :{SMALLFONT}{BLACK}Bouw park ingang -STR_3227 :Te veel park ingangen! -STR_3228 :{SMALLFONT}{BLACK}Geef start posities voor bezoekers aan +STR_3215 :Te dicht bij de rand van de kaart +STR_3216 :{SMALLFONT}{BLACK}Selecteer parkland, etc. +STR_3217 :Eigendom van het park +STR_3218 :Bouwrechten voor het park +STR_3219 :Te koop +STR_3220 :Bouwrechten te koop +STR_3221 :{SMALLFONT}{BLACK}Instellen welk land van het park is +STR_3222 :{SMALLFONT}{BLACK}Instellen voor welk land het park bouwrechten heeft +STR_3223 :{SMALLFONT}{BLACK}Instellen welk land gekocht kan worden door het park +STR_3224 :{SMALLFONT}{BLACK}Instellen voor welk land bouwrechten te koop zijn +STR_3225 :{SMALLFONT}{BLACK}Een willekeurig cluster van dit object neerzetten rondom de geselecteerde plek +STR_3226 :{SMALLFONT}{BLACK}Parkingang bouwen +STR_3227 :Teveel parkingangen! +STR_3228 :{SMALLFONT}{BLACK}Geef startposities voor bezoekers aan STR_3229 :Blokremmen kunnen niet direct na het station geplaatst worden STR_3230 :Blokremmen kunnen niet direct achter elkaar gebruikt worden -STR_3231 :Blokremmen kunnen niet direct achter de top van een liftheuvel geplaatst worden -STR_3232 :Opties - Financiëel +STR_3231 :Blokremmen kunnen niet direct achter de top van een kettingheuvel geplaatst worden +STR_3232 :Opties - Financiën STR_3233 :Opties - Bezoekers STR_3234 :Opties - Park STR_3235 :{SMALLFONT}{BLACK}Toon financiële opties -STR_3236 :{SMALLFONT}{BLACK}Toon bezoekrs opties -STR_3237 :{SMALLFONT}{BLACK}Toon park opties +STR_3236 :{SMALLFONT}{BLACK}Toon bezoekersopties +STR_3237 :{SMALLFONT}{BLACK}Toon parkopties STR_3238 :Zonder geld -STR_3239 :{SMALLFONT}{BLACK}Maak dit park 'zonder geld' zodat je oneindig veel geld hebt +STR_3239 :{SMALLFONT}{BLACK}Schakel geld compleet uit, zodat het park geen financiële beperkingen heeft STR_3240 :{WINDOW_COLOUR_2}Startsaldo: STR_3241 :{WINDOW_COLOUR_2}Startlening STR_3242 :{WINDOW_COLOUR_2}Maximale lening: @@ -3246,20 +3246,20 @@ STR_3244 :Marketingcampagnes niet toestaan STR_3245 :{SMALLFONT}{BLACK}Geen advertenties, promoties of andere marketingacties toestaan STR_3246 :{WINDOW_COLOUR_2}{CURRENCY} STR_3247 :{WINDOW_COLOUR_2}{COMMA16}% -STR_3248 :Kan aanvankelijke hoeveelheid geld niet verder verhogen! -STR_3249 :Kan aanvankelijke hoeveelheid geld niet verder verlagen! -STR_3250 :Kan aanvankelijke lening niet verder verhogen! -STR_3251 :Kan aanvankelijke lening niet verder verlagen! -STR_3252 :Kan maximale lening niet verder vergroten! -STR_3253 :Kan maximale lening niet verder verkleinen! -STR_3254 :Kan rente niet verder verhogen! -STR_3255 :Kan rente niet verder verlagen! +STR_3248 :Kan het startsaldo niet verder verhogen! +STR_3249 :Kan het startsaldo niet verder verlagen! +STR_3250 :Kan de startlening niet verder verhogen! +STR_3251 :Kan de startlening niet verder verlagen! +STR_3252 :Kan de maximumlening niet verder verhogen! +STR_3253 :Kan de maximumlening niet verder verlagen! +STR_3254 :Kan de rente niet verder verhogen! +STR_3255 :Kan de rente niet verder verlagen! STR_3256 :Bezoekers houden meer van rustigere attracties STR_3257 :{SMALLFONT}{BLACK}Selecteer of bezoekers in het algemeen meer van rustigere attracties houden STR_3258 :Bezoekers houden meer van spannende attracties STR_3259 :{SMALLFONT}{BLACK}Selecteer of bezoekers in het algemeen meer van spannende attracties houden STR_3260 :{WINDOW_COLOUR_2}Geld per bezoeker (gemiddeld): -STR_3261 :{WINDOW_COLOUR_2}Aanvankelijke blijheid bezoekers: +STR_3261 :{WINDOW_COLOUR_2}Aanvankelijke stemming bezoekers: STR_3262 :{WINDOW_COLOUR_2}Aanvankelijke honger bezoekers: STR_3263 :{WINDOW_COLOUR_2}Aanvankelijke dorst bezoekers: STR_3264 :Kan dit niet verder verhogen! @@ -3269,22 +3269,22 @@ STR_3267 :Verbied verwijderen bomen STR_3268 :{SMALLFONT}{BLACK}Verbied het verwijderen van bomen STR_3269 :Verbied veranderen landschap STR_3270 :{SMALLFONT}{BLACK}Verbied het veranderen van het landschap -STR_3271 :Verbied hoge constructie -STR_3272 :{SMALLFONT}{BLACK}Verbied het bouwen van hoge constructies +STR_3271 :Verbied hoog bouwen +STR_3272 :{SMALLFONT}{BLACK}Verbied bouwen boven boomhoogte STR_3273 :Hogere moeilijkheid parkwaardering -STR_3274 :{SMALLFONT}{BLACK}Maak de parkwaardering meer uitdagend +STR_3274 :{SMALLFONT}{BLACK}Maak het krijgen van een goede parkwaardering uitdagender STR_3275 :Hogere moeilijkheid bezoekersgeneratie -STR_3276 :{SMALLFONT}{BLACK}Maak het moeilijker om gasten aan te trekken naar je park te komen -STR_3277 :{WINDOW_COLOUR_2}Landkoop kosten: -STR_3278 :{WINDOW_COLOUR_2}Constructierechten kosten: +STR_3276 :{SMALLFONT}{BLACK}Maak het moeilijker om bezoekers aan te trekken +STR_3277 :{WINDOW_COLOUR_2}Prijs landaankoop: +STR_3278 :{WINDOW_COLOUR_2}Prijs bouwrechten: STR_3279 :Gratis entree / Per rit betalen STR_3280 :Betaalde toegang / Attracties gratis STR_3281 :{WINDOW_COLOUR_2}Entreeprijs: -STR_3282 :{SMALLFONT}{BLACK}Selecteer doelstellingen en parknaam -STR_3283 :{SMALLFONT}{BLACK}Selecteer attracties die beschermd moeten blijven +STR_3282 :{SMALLFONT}{BLACK}Doel en parknaam selecteren +STR_3283 :{SMALLFONT}{BLACK}Beschermde attracties selecteren STR_3284 :Doelselectie STR_3285 :Beschermde attracties -STR_3286 :{SMALLFONT}{BLACK}Selecteer doelstellingen voor dit scenario +STR_3286 :{SMALLFONT}{BLACK}Selecteer doel voor dit scenario STR_3287 :{WINDOW_COLOUR_2}Doel: STR_3288 :{SMALLFONT}{BLACK}Selecteer klimaat: STR_3289 :{WINDOW_COLOUR_2}Klimaat: @@ -3295,75 +3295,75 @@ STR_3293 :Koud STR_3294 :Aanpassen... STR_3295 :{SMALLFONT}{BLACK}Parknaam veranderen STR_3296 :{SMALLFONT}{BLACK}Scenarionaam veranderen -STR_3297 :{SMALLFONT}{BLACK}Change detail notes about park / scenario +STR_3297 :{SMALLFONT}{BLACK}Details van dit park/scenario aanpassen STR_3298 :{WINDOW_COLOUR_2}Parknaam: {BLACK}{STRINGID} -STR_3299 :{WINDOW_COLOUR_2}Park/Scenario Details: -STR_3300 :{WINDOW_COLOUR_2}Scenario Naam: {BLACK}{STRINGID} -STR_3301 :{WINDOW_COLOUR_2}Datum doelstellingen: +STR_3299 :{WINDOW_COLOUR_2}Parkdetails: +STR_3300 :{WINDOW_COLOUR_2}Scenarionaam: {BLACK}{STRINGID} +STR_3301 :{WINDOW_COLOUR_2}Datum doel: STR_3302 :{WINDOW_COLOUR_2}{MONTHYEAR} STR_3303 :{WINDOW_COLOUR_2}Aantal bezoekers: STR_3304 :{WINDOW_COLOUR_2}Parkwaarde: -STR_3305 :{WINDOW_COLOUR_2}Maandelijkse inkomst: -STR_3306 :{WINDOW_COLOUR_2}Maandelijke winst: -STR_3307 :{WINDOW_COLOUR_2}Minimale lengte: -STR_3308 :{WINDOW_COLOUR_2}Opwindingscijfer: +STR_3305 :{WINDOW_COLOUR_2}Maandelijkse inkomsten: +STR_3306 :{WINDOW_COLOUR_2}Maandelijkse winst: +STR_3307 :{WINDOW_COLOUR_2}Minimumlengte: +STR_3308 :{WINDOW_COLOUR_2}Spanningswaarde: STR_3309 :{WINDOW_COLOUR_2}{COMMA16} STR_3310 :{WINDOW_COLOUR_2}{LENGTH} STR_3311 :{WINDOW_COLOUR_2}{COMMA2DP32} -STR_3312 :{WINDOW_COLOUR_2}Attracties die beschermd moeten worden: +STR_3312 :{WINDOW_COLOUR_2}Attracties met monumentenstatus: STR_3313 :Scenarionaam -STR_3314 :Geef naam voor scenario:- -STR_3315 :Park/Scenario Details -STR_3316 :Geef een beschrijving van die scenario:- +STR_3314 :Voer een naam in voor het scenario: +STR_3315 :Details park/scenario +STR_3316 :Geef een beschrijving voor dit scenario: STR_3317 :Nog geen details -STR_3318 :{SMALLFONT}{BLACK}Selecteer in welke groep dit scenario terechtkomt -STR_3319 :{WINDOW_COLOUR_2}Scenario Groep: +STR_3318 :{SMALLFONT}{BLACK}Selecteer in welke groep dit scenario moet verschijnen +STR_3319 :{WINDOW_COLOUR_2}Scenariogroep: STR_3320 :Kan scenariobestand niet opslaan... STR_3321 :Nieuwe objecten successvol geïnstalleerd -STR_3322 :{WINDOW_COLOUR_2}Doelstelling: {BLACK}{STRINGID} -STR_3323 :Vermiste object data, ID: +STR_3322 :{WINDOW_COLOUR_2}Doel: {BLACK}{STRINGID} +STR_3323 :Ontbrekende objectdata, ID: STR_3324 :Vereist uitbreidingspakket: STR_3325 :Vereist een uitbreidingspakket STR_3326 :{WINDOW_COLOUR_2}(geen plaatje) STR_3327 :Startpositie voor bezoekers niet aangegeven STR_3328 :Kan niet verder naar volgende stap... -STR_3329 :Park ingang nog niet gebouwd -STR_3330 :Park moet wat land bezitten -STR_3331 :Pad van park ingang naar kaart rand niet compleet of te complex - Pad moet 1 breed zijn met zo min mogelijk kruisingen en bochten als mogelijk -STR_3332 :Park ingang staat verkeerdom of heeft geen pad naar de kaart rand -STR_3333 :Exporteer plug-in objecten met opgeslagen games -STR_3334 :{SMALLFONT}{BLACK}Select whether to save any additional plug-in object data required (add-in data not supplied with the main product) in saved game or scenario files, allowing them to be loaded by someone who doesn't have the additional object data -STR_3335 :Achtbaanontwerper - Selecteer Attractie- & Karretjestype -STR_3336 :Baanontwerpbeheer - Selecteer Karretjestype +STR_3329 :Parkingang nog niet gebouwd +STR_3330 :Park moet land bezitten +STR_3331 :Pad van de parkingang naar de rand van de kaart is incompleet of te complex - het pad mag maar één blok breed zijn en moet zo min mogelijk kruisingen en bochten bevatten +STR_3332 :Parkingang staan achterstevoren of heeft geen pad naar de rand van de kaart +STR_3333 :Niet-standaard objecten meeleveren in opgeslagen spellen +STR_3334 :{SMALLFONT}{BLACK}Selecteer of toegevoegde (niet-standaard) objecten in opgeslagen spellen en scenario's moeten worden meegeleverd, zodat ze geopend kunnen worden door iemand die deze objecten nog niet heeft +STR_3335 :Achtbaanontwerper - Attractietypes en -voertuigen selecteren +STR_3336 :Baanontwerpbeheer - Attractietype selecteren STR_3337 :Six Flags-park -STR_3338 :{BLACK}Zelfontworpen opmaak -STR_3339 :{BLACK}{COMMA16} ontwerp beschikbaar, of ontwerp zelf -STR_3340 :{BLACK}{COMMA16} ontwerpen beschikbaar, of ontwerp zelf -STR_3341 :{SMALLFONT}{BLACK}Spel gereedschap -STR_3342 :Scenario Editor -STR_3343 :Zet Opgeslagen Spel om tot Scenario +STR_3338 :{BLACK}Eigen ontwerp +STR_3339 :{BLACK}{COMMA16} ontwerp beschikbaar, of maak een eigen ontwerp +STR_3340 :{BLACK}{COMMA16} ontwerpen beschikbaar, of maak een eigen ontwerp +STR_3341 :{SMALLFONT}{BLACK}Hulpmiddelen +STR_3342 :Scenariobewerker +STR_3343 :Opgeslagen spel omzetten naar scenario STR_3344 :Achtbaanontwerper STR_3345 :Baanontwerpbeheer -STR_3346 :Kan baanontwerp niet opslaan... -STR_3347 :Attractie is te groot, bezit teveel dingen, of het decor is te wijd verspreid +STR_3346 :Kan baanontwerp niet opslaan +STR_3347 :Attractie is te groot, bevat teveel elementen, of het decor is te ver verspreid STR_3348 :Naam wijzigen STR_3349 :Verwijderen STR_3350 :Naam baanontwerp -STR_3351 :Voer nieuwe naam in voor dit baanontwerp:- -STR_3352 :Kan baanontwerp geen nieuwe naam geven... -STR_3353 :Nieuwe naam bezit ongeldige karakters -STR_3354 :Een bestand bestaat al met deze naam, of het bestand is schrijf-beschermd -STR_3355 :Bestand is schrijf-beschermd of vergrendeld -STR_3356 :Verwijder Bestand -STR_3357 :{WINDOW_COLOUR_2}Weet je zeker dat je {STRINGID} voor altijd wil verwijderen? -STR_3358 :Kan baanontwerp niet verwijderen... -STR_3359 :{BLACK}Geen baanontwerp van dit type -STR_3360 :Warschuwing! -STR_3361 :Te veel baanontwerpen van dit type - Sommige staan niet in de lijst +STR_3351 :Voer een nieuwe naam in voor dit baanontwerp: +STR_3352 :Kan het baanontwerp geen andere naam geven... +STR_3353 :Nieuwe naam bevat ongeldige tekens +STR_3354 :Er bestaat al een bestand met deze naam, of het bestand is beveiligd tegen schrijven +STR_3355 :Bestand is beveiligd tegen schrijven of vergrendeld +STR_3356 :Bestand verwijderen +STR_3357 :{WINDOW_COLOUR_2}Weet je zeker dat je {STRINGID} permanent wilt verwijderen? +STR_3358 :Kan het baanontwerp niet verwijderen... +STR_3359 :{BLACK}Geen baanontwerpen van dit type +STR_3360 :Waarschuwing! +STR_3361 :Te veel baanontwerpen van dit type - sommige staan niet in de lijst STR_3362 :Mixing via softwarebuffer forceren -STR_3363 :{SMALLFONT}{BLACK}Select this option to improve performance if the game pauses slightly when sounds start or interference is heard +STR_3363 :{SMALLFONT}{BLACK}Selecteer deze optie om de prestaties te verbeteren als het spel vertraagt bij het afspelen van geluiden of als er ruis hoorbaar is STR_3364 :Meer opties -STR_3365 :{SMALLFONT}{BLACK}sta selectie van individuele decoritems toe naast decorgroepen +STR_3365 :{SMALLFONT}{BLACK}Maakt naast selectie van decorgroepen ook selectie van losse items mogelijk STR_3366 :{BLACK}= Attractie STR_3367 :{BLACK}= Eetkraampje STR_3368 :{BLACK}= Drankkraampje @@ -3372,70 +3372,70 @@ STR_3370 :{BLACK}= Infokiosk STR_3371 :{BLACK}= Eerste hulp STR_3372 :{BLACK}= PIN STR_3373 :{BLACK}= Toilet -STR_3374 :Waarschuwing: Te veel objecten geselecteerd! +STR_3374 :Waarschuwing: teveel objecten geselecteerd! STR_3375 :Niet alle objecten in deze decorgroep kunnen worden geselecteerd -STR_3376 :Installeer nieuw baanontwerp... -STR_3377 :{SMALLFONT}{BLACK}Installeer een nieuw baanontwerp +STR_3376 :Nieuw baanontwerp installeren... +STR_3377 :{SMALLFONT}{BLACK}Bestand met nieuw baanontwerp installeren STR_3378 :Installeren STR_3379 :Annuleren -STR_3380 :Kan baanontwerp niet installeren... -STR_3381 :Bestand is niet verenigbaar of bezit ongeldige data -STR_3382 :Bestand kopïeren gefaald +STR_3380 :Kan dit baanontwerp niet installeren... +STR_3381 :Bestand is niet compatible of bevat ongeldige gegevens +STR_3382 :Kopiëren van bestand mislukt STR_3383 :Selecteer nieuwe naam voor dit baanontwerp -STR_3384 :Er bestaat al een baanontwerp met deze naam - Verzin een andere naam voor dit ontwerp: -STR_3385 :Snelcursus voor Beginners -STR_3386 :Snelcursus Zelfontworpen Attracties -STR_3387 :Snelcursus Achtbanen Bouwen -STR_3388 :Kan niet naar geselecteerde modus wisselen -STR_3389 :Kan additionele decorstukken niet selecteren... +STR_3384 :Er bestaat al een baanontwerp met deze naam - verzin een andere naam voor dit ontwerp: +STR_3385 :Tutorial voor beginners +STR_3386 :Toturial voor eigen ontwerpen +STR_3387 :Toturial voor achtbanen bouwen +STR_3388 :Kan niet naar de geselecteerde modus overschakelen +STR_3389 :Kan extra decorstukken niet selecteren... STR_3390 :Te veel items geselecteerd -STR_3391 :{SMALLFONT}{BLACK}Dit is ons park - Laten we eventjes kort rondkijken... -STR_3392 :{SMALLFONT}{BLACK}De snelste manier om het beeld te verschuiven is de RECHTER muisknop inhouden en met de muis bewegen... -STR_3393 :{SMALLFONT}{BLACK}Als je meer van het park wil zien, kan je uitzoomen met het icoontje bovenaan het scherm... -STR_3394 :{SMALLFONT}{BLACK}Je kan het beeld ook draaien in stappen van 90 graden... -STR_3395 :{SMALLFONT}{BLACK}Dingen bouwen vanaf deze hoogte word een beetje lastig, laten we terug inzoomen... +STR_3391 :{SMALLFONT}{BLACK}Dit is ons park - laten we eventjes kort rondkijken... +STR_3392 :{SMALLFONT}{BLACK}De snelste manier om het beeld te verschuiven is de RECHTERmuisknop inhouden en met de muis bewegen... +STR_3393 :{SMALLFONT}{BLACK}Als je meer van het park wil zien, kan je uitzoomen met het knopje bovenaan het scherm... +STR_3394 :{SMALLFONT}{BLACK}Je kunt het beeld ook draaien in stappen van 90 graden... +STR_3395 :{SMALLFONT}{BLACK}Dingen bouwen vanaf deze hoogte is een beetje lastig, laten we terug inzoomen... STR_3396 :{SMALLFONT}{BLACK}Laten we een simpele attractie bouwen om met dit park te beginnen... -STR_3397 :{SMALLFONT}{BLACK}Het witte 'spook' plaatje laat zien waar de attractie zal worden gebouwd. Beweeg de muis er naar toe en klik om het te bouwen... +STR_3397 :{SMALLFONT}{BLACK}Het witte 'spookplaatje' laat zien waar de attractie zal worden gebouwd. Beweeg de muis er naar toe en klik om het te bouwen... STR_3398 :{SMALLFONT}{BLACK}Attracties hebben een ingang en een uitgang nodig. Beweeg de muis naar een tegeltje aan de rand van de attractie en klik om de ingang te bouwen. Klik nog een keer ergens om de uitgang te bouwen... STR_3399 :{SMALLFONT}{BLACK}We moeten een voetpad bouwen zodat bezoekers onze nieuwe attractie kunnen bereiken... -STR_3400 :{SMALLFONT}{BLACK}Voor het pad naar de ingang gebruiken we een speciaal 'wachtrij' pad... -STR_3401 :{SMALLFONT}{BLACK}Voor de uitgang maakt het niet uit welk pad je gebruikt. Een 'normaal' pad is goed... -STR_3402 :{SMALLFONT}{BLACK}Okay dan, laten we de attractie openen! Om de attractie te openen klikken we op het vlag icoontje in het attractievenster en selecteren we 'openen'... +STR_3400 :{SMALLFONT}{BLACK}Voor het pad naar de ingang gebruiken we een speciaal wachtrij-voetpad... +STR_3401 :{SMALLFONT}{BLACK}Voor de uitgang maakt het niet uit welk pad je gebruikt. Een normaal pad is goed... +STR_3402 :{SMALLFONT}{BLACK}Oké dan, laten we de attractie openen! Om de attractie te openen klikken we op het knopje met de vlag in het attractievenster en selecteren we 'openen'... STR_3403 :{SMALLFONT}{BLACK}Maar waar zijn de bezoekers?! STR_3404 :{SMALLFONT}{BLACK}Oh, juist - het park is nog gesloten! Laten we ons park openen... STR_3405 :{SMALLFONT}{BLACK}Terwijl we op onze eerste bezoekers wachten kunnen we wat decorstukken neerzetten... STR_3406 :{SMALLFONT}{BLACK}Dit is ons lege park. We gaan een simpele zelfontworpen attractie bouwen... STR_3407 :{SMALLFONT}{BLACK}Ten eerste hebben we een startpositie nodig... -STR_3408 :{SMALLFONT}{BLACK}Het stuk baan dat we net gebouwd hebben is een 'station platform', en zorgt ervoor dat bezoekers in en uit kunnen stappen... -STR_3409 :{SMALLFONT}{BLACK}We verlengen het platform een beetje door nog wat station platform secties aan te leggen... -STR_3410 :{SMALLFONT}{BLACK}De icoontjes aan de bovenkant van het constructievenster laten je tusen verschillende soorten baanstukjes kiezen... +STR_3408 :{SMALLFONT}{BLACK}Het stuk baan dat we net gebouwd hebben is een 'station', en zorgt ervoor dat bezoekers in en uit kunnen stappen... +STR_3409 :{SMALLFONT}{BLACK}We verlengen het perron een beetje door nog wat stationssegmenten aan te leggen... +STR_3410 :{SMALLFONT}{BLACK}De knopjes aan de bovenkant van het bouwvenster laten je tusen verschillende soorten baanstukjes kiezen... STR_3411 :{SMALLFONT}{BLACK}We gaan een bocht naar links bouwen... -STR_3412 :{SMALLFONT}{BLACK}De bocht is nog niet gebouwt, maar het witte spookplaatje laat zien waar het gebouwd gaat worden. Als je op het grote 'bouw dit' icoontje klikt word het gebouwd... -STR_3413 :{SMALLFONT}{BLACK}Nu willen we een recht stuk bouwen, dus klikken we op het rechte stuk icoontjes... -STR_3414 :{SMALLFONT}{BLACK}Nu dat het circuit compleet is, kunnen we de ingang en uitgang bouwen... +STR_3412 :{SMALLFONT}{BLACK}De bocht is nog niet gebouwd, maar het witte spookplaatje laat zien waar het gebouwd gaat worden. Als je op de grote knop klikt wordt het gebouwd... +STR_3413 :{SMALLFONT}{BLACK}Nu willen we een recht stuk bouwen, dus klikken we op het knopje voor 'recht stuk'... +STR_3414 :{SMALLFONT}{BLACK}De baan is af, we kunnen nu de ingang en uitgang bouwen... STR_3415 :{SMALLFONT}{BLACK}Laten we testen of onze attractie werkt... -STR_3416 :{SMALLFONT}{BLACK}Terwijl het word getest kunnen we een wachtrij en uitgang pad bouwen... +STR_3416 :{SMALLFONT}{BLACK}Terwijl de attractie wordt getest kunnen we een wachtrij en uitgangspad bouwen... STR_3417 :{SMALLFONT}{BLACK}Goed - laten we het park en onze attractie openen... STR_3418 :{SMALLFONT}{BLACK}Onze nieuwe attractie is niet heel erg spannend - misschien moeten we wat decor toevoegen? -STR_3419 :{SMALLFONT}{BLACK}Om decor te bouwen boven ander decor (of midden in de lucht) hou je de SHIFT toets ingedrukt en beweeg je de muis om de hoogte te bepalen... -STR_3420 :{SMALLFONT}{BLACK}Sommige types decor kunnen overgeverft worden nadat ze gebouwd zijn... -STR_3421 :{SMALLFONT}{BLACK}Laten we wat muziek toevoegen aan onze attractie... +STR_3419 :{SMALLFONT}{BLACK}Om decor te bouwen boven ander decor (of midden in de lucht) hou je de SHIFT-toets ingedrukt en beweeg je de muis om de hoogte te bepalen... +STR_3420 :{SMALLFONT}{BLACK}Sommige types decor kunnen opnieuw geverfd worden nadat ze zijn gebouwd... +STR_3421 :{SMALLFONT}{BLACK}Laten we wat muziek draaien in onze attractie... STR_3422 :{SMALLFONT}{BLACK}Laten we een achtbaan bouwen! -STR_3423 :{SMALLFONT}{BLACK}Er zijn tonnen met voorafgebouwde achtbanen, maar wij gaan ons eigen ontwerp bouwen... -STR_3424 :{SMALLFONT}{BLACK}Zo, dat is het station platform. Nu hebben we een liftheuvel nodig... +STR_3423 :{SMALLFONT}{BLACK}Er zijn veel kant-en-klare achtbanen, maar wij gaan ons eigen ontwerp bouwen... +STR_3424 :{SMALLFONT}{BLACK}Zo, het station is af. Nu hebben we een liftheuvel nodig... STR_3425 :{SMALLFONT}{BLACK}Achtbaankarretjes zijn niet aangedreven, dus is een 'kettinglift' nodig om ze eerst een heuvel op te trekken... -STR_3426 :{SMALLFONT}{BLACK}Okay, de liftheuvel is klaar - Nu voor de eerste afdaling... -STR_3427 :{SMALLFONT}{BLACK}Die bochten zijn een slecht idee - De rijders zullen naar de zijkanten gesmeten worden terwijl de trein er overheen dondert... -STR_3428 :{SMALLFONT}{BLACK}De bochten een banking geven zal de rit prettiger maken - Rijders zullen in hun stoelen geduwt worden in plaats van naar de zijkanten... -STR_3429 :{SMALLFONT}{BLACK}Ja dat wordt em dus niet! Kijk naar de hoogtemarkeringen - De tweede heuvel is hoger dan de liftheuvel... -STR_3430 :{SMALLFONT}{BLACK}Om ervoor te zorgen dat de trein terug naar het station komt, moet elke heuevel iets lager zijn dan de heuvel daarvoor... +STR_3426 :{SMALLFONT}{BLACK}Goed, de liftheuvel is klaar - nu de eerste afdaling... +STR_3427 :{SMALLFONT}{BLACK}Die bochten zijn een slecht idee - de passagiers zullen naar de zijkanten gesmeten worden wanneer de trein er doorheen raast... +STR_3428 :{SMALLFONT}{BLACK}De bochten een banking (schuinleggen) geven zal de rit prettiger maken - de passagiers zullen in hun stoelen geduwd worden in plaats van naar de zijkanten... +STR_3429 :{SMALLFONT}{BLACK}Dit gaat niet werken! Kijk naar de hoogtemarkeringen - De tweede heuvel is hoger dan de liftheuvel... +STR_3430 :{SMALLFONT}{BLACK}Om ervoor te zorgen dat de trein terug naar het station komt, moet elke heuvel iets lager zijn dan de heuvel daarvoor... STR_3431 :{SMALLFONT}{BLACK}Dat ziet er beter uit! Onze trein zou het nu moeten halen! Laten we wat meer bochtige stukjes toevoegen... STR_3432 :{SMALLFONT}{BLACK}We moeten de trein afremmen voordat we de laatste bocht en het station inkomen, dus laten we wat remmen toevoegen... STR_3433 :{SMALLFONT}{BLACK}En tenslotte voegen we 'blokremmen' toe. Die zorgen ervoor dat twee treinen tegelijk (en veilig) op de baan kunnen zitten... STR_3434 :{SMALLFONT}{BLACK}Laten we kijken of onze achtbaan werkt! -STR_3435 :{SMALLFONT}{BLACK}Fantastisch - Hij werkt! Laten we wat voetpaden aanleggen zodat bezoekers bij onze nieuwe achtbaan kunnen komen... -STR_3436 :{SMALLFONT}{BLACK}Terwijl we wachten op onze eerste rijders, kunnen we onze achtbaan een beetje aanpassen... -STR_3437 :{SMALLFONT}{BLACK}Verwijder grote gebieden decor van het landschap +STR_3435 :{SMALLFONT}{BLACK}Fantastisch - hij werkt! Laten we wat voetpaden aanleggen zodat bezoekers bij onze nieuwe achtbaan kunnen komen... +STR_3436 :{SMALLFONT}{BLACK}Terwijl we wachten op onze eerste bezoekers, kunnen we onze achtbaan een beetje aanpassen... +STR_3437 :{SMALLFONT}{BLACK}Grote gebieden met decor van het landschap verwijderen STR_3438 :Kan hier niet al het decor verwijderen... STR_3439 :Decor verwijderen STR_3440 :Pagina 1 diff --git a/data/language/english_uk.txt b/data/language/english_uk.txt index 23535f2a06..a6b4cc889a 100644 --- a/data/language/english_uk.txt +++ b/data/language/english_uk.txt @@ -2526,6 +2526,7 @@ STR_2521 :Show staff list STR_2522 :Show recent messages STR_2523 :Show map STR_2524 :Screenshot +### The following need to be reordered to match SDL_keycode layout. STR_2525 :??? STR_2526 :??? STR_2527 :??? diff --git a/data/language/swedish.txt b/data/language/swedish.txt new file mode 100644 index 0000000000..70a9d8cce5 --- /dev/null +++ b/data/language/swedish.txt @@ -0,0 +1,3456 @@ +# STR_XXXX part is read and XXXX becomes the string id number. +# Everything after the colon and before the new line will be saved as the string. +# Use # at the beginning of a line to leave a comment. +STR_0000 : +STR_0001 :{STRINGID} {COMMA16} +STR_0002 :Åktur +STR_0003 :Åktur +STR_0004 :Hängande svängande bana +STR_0005 :Åktur +STR_0006 :Junior berg- och dalbana +STR_0007 :Miniatyr-tåg +STR_0008 :Balkbana +STR_0009 :Liten hängande bana +STR_0010 :Åktur +STR_0011 :Åktur +STR_0012 :Åktur +STR_0013 :Bilåktur +STR_0014 :Åktur +STR_0015 :Åktur +STR_0016 :Åktur +STR_0017 :Loopande berg- och dalbana +STR_0018 :Åktur +STR_0019 :Åktur +STR_0020 :Stolslift +STR_0021 :Åktur +STR_0022 :Åktur +STR_0023 :Åktur +STR_0024 :Åktur +STR_0025 :Åktur +STR_0026 :Åktur +STR_0027 :Åktur +STR_0028 :Åktur +STR_0029 :Åktur +STR_0030 :Stånd +STR_0031 :Stånd +STR_0032 :Stånd +STR_0033 :Stånd +STR_0034 :Stånd +STR_0035 :Åktur +STR_0036 :Stånd +STR_0037 :Kiosk +STR_0038 :Toalett +STR_0039 :Åktur +STR_0040 :Åktur +STR_0041 :Åktur +STR_0042 :Åktur +STR_0043 :Åktur +STR_0044 :Bakvänd fritt fall-bana +STR_0045 :Lift +STR_0046 :Åktur +STR_0047 :Åktur +STR_0048 :Åktur +STR_0049 :Åktur +STR_0050 :Åktur +STR_0051 :Åktur +STR_0052 :Åktur +STR_0053 :Hyper-snurr berg- och dalbana +STR_0054 :Berg- och dalbana i trä +STR_0055 :Sidofriktion berg- och dalbana +STR_0056 :Vilda Musen +STR_0057 :Flerdimensionell berg- och dalbana +STR_0058 :Åktur +STR_0059 :Inverterad berg- och dalbana +STR_0060 :Åktur +STR_0061 :Åktur +STR_0062 :Åktur +STR_0063 :Åktur +STR_0064 :Åktur +STR_0065 :Hängande balkbana +STR_0066 :Åktur +STR_0067 :Åktur +STR_0068 :Skruvbana +STR_0069 :Åktur +STR_0070 :Åktur +STR_0071 :Åktur +STR_0072 :Åktur +STR_0073 :Åktur +STR_0074 :Åktur +STR_0075 :Åktur +STR_0076 :Vattenbana +STR_0077 :Åktur +STR_0078 :Åktur +STR_0079 :Åktur +STR_0080 :Åktur +STR_0081 :Åktur +STR_0082 :Åktur +STR_0083 :Åktur +STR_0084 :Åktur +STR_0085 :Åktur +STR_0086 :Åktur +STR_0087 :Åktur +STR_0088 :Åktur +STR_0089 :Mini berg- och dalbana +STR_0090 :Åktur +STR_0091 :Åktur +STR_0092 :Åktur +STR_0093 : +STR_0094 : +STR_0095 : +STR_0096 : +STR_0097 : +STR_0098 : +STR_0099 : +STR_0100 : +STR_0101 : +STR_0102 : +STR_0103 : +STR_0104 : +STR_0105 : +STR_0106 : +STR_0107 : +STR_0108 : +STR_0109 : +STR_0110 : +STR_0111 : +STR_0112 : +STR_0113 : +STR_0114 : +STR_0115 : +STR_0116 : +STR_0117 : +STR_0118 : +STR_0119 : +STR_0120 : +STR_0121 : +STR_0122 : +STR_0123 : +STR_0124 : +STR_0125 : +STR_0126 : +STR_0127 : +STR_0128 : +STR_0129 : +STR_0130 : +STR_0131 : +STR_0132 : +STR_0133 : +STR_0134 : +STR_0135 : +STR_0136 : +STR_0137 : +STR_0138 : +STR_0139 : +STR_0140 : +STR_0141 : +STR_0142 : +STR_0143 : +STR_0144 : +STR_0145 : +STR_0146 : +STR_0147 : +STR_0148 : +STR_0149 : +STR_0150 : +STR_0151 : +STR_0152 : +STR_0153 : +STR_0154 : +STR_0155 : +STR_0156 : +STR_0157 : +STR_0158 : +STR_0159 : +STR_0160 : +STR_0161 : +STR_0162 : +STR_0163 : +STR_0164 : +STR_0165 : +STR_0166 : +STR_0167 : +STR_0168 : +STR_0169 : +STR_0170 : +STR_0171 : +STR_0172 : +STR_0173 : +STR_0174 : +STR_0175 : +STR_0176 : +STR_0177 : +STR_0178 : +STR_0179 : +STR_0180 : +STR_0181 : +STR_0182 : +STR_0183 : +STR_0184 : +STR_0185 : +STR_0186 : +STR_0187 : +STR_0188 : +STR_0189 : +STR_0190 : +STR_0191 : +STR_0192 : +STR_0193 : +STR_0194 : +STR_0195 : +STR_0196 : +STR_0197 : +STR_0198 : +STR_0199 : +STR_0200 : +STR_0201 : +STR_0202 : +STR_0203 : +STR_0204 : +STR_0205 : +STR_0206 : +STR_0207 : +STR_0208 : +STR_0209 : +STR_0210 : +STR_0211 : +STR_0212 : +STR_0213 : +STR_0214 : +STR_0215 : +STR_0216 : +STR_0217 : +STR_0218 : +STR_0219 : +STR_0220 : +STR_0221 : +STR_0222 : +STR_0223 : +STR_0224 : +STR_0225 : +STR_0226 : +STR_0227 : +STR_0228 : +STR_0229 : +STR_0230 : +STR_0231 : +STR_0232 : +STR_0233 : +STR_0234 : +STR_0235 : +STR_0236 : +STR_0237 : +STR_0238 : +STR_0239 : +STR_0240 : +STR_0241 : +STR_0242 : +STR_0243 : +STR_0244 : +STR_0245 : +STR_0246 : +STR_0247 : +STR_0248 : +STR_0249 : +STR_0250 : +STR_0251 : +STR_0252 : +STR_0253 : +STR_0254 : +STR_0255 : +STR_0256 : +STR_0257 : +STR_0258 : +STR_0259 : +STR_0260 : +STR_0261 : +STR_0262 : +STR_0263 : +STR_0264 : +STR_0265 : +STR_0266 : +STR_0267 : +STR_0268 : +STR_0269 : +STR_0270 : +STR_0271 : +STR_0272 : +STR_0273 : +STR_0274 : +STR_0275 : +STR_0276 : +STR_0277 : +STR_0278 : +STR_0279 : +STR_0280 : +STR_0281 : +STR_0282 : +STR_0283 : +STR_0284 : +STR_0285 : +STR_0286 : +STR_0287 : +STR_0288 : +STR_0289 : +STR_0290 : +STR_0291 : +STR_0292 : +STR_0293 : +STR_0294 : +STR_0295 : +STR_0296 : +STR_0297 : +STR_0298 : +STR_0299 : +STR_0300 : +STR_0301 : +STR_0302 : +STR_0303 : +STR_0304 : +STR_0305 : +STR_0306 : +STR_0307 : +STR_0308 : +STR_0309 : +STR_0310 : +STR_0311 : +STR_0312 : +STR_0313 : +STR_0314 : +STR_0315 : +STR_0316 : +STR_0317 : +STR_0318 : +STR_0319 : +STR_0320 : +STR_0321 : +STR_0322 : +STR_0323 : +STR_0324 : +STR_0325 : +STR_0326 : +STR_0327 : +STR_0328 : +STR_0329 : +STR_0330 : +STR_0331 : +STR_0332 : +STR_0333 : +STR_0334 : +STR_0335 : +STR_0336 : +STR_0337 : +STR_0338 : +STR_0339 : +STR_0340 : +STR_0341 : +STR_0342 : +STR_0343 : +STR_0344 : +STR_0345 : +STR_0346 : +STR_0347 : +STR_0348 : +STR_0349 : +STR_0350 : +STR_0351 : +STR_0352 : +STR_0353 : +STR_0354 : +STR_0355 : +STR_0356 : +STR_0357 : +STR_0358 : +STR_0359 : +STR_0360 : +STR_0361 : +STR_0362 : +STR_0363 : +STR_0364 : +STR_0365 : +STR_0366 : +STR_0367 : +STR_0368 : +STR_0369 : +STR_0370 : +STR_0371 : +STR_0372 : +STR_0373 : +STR_0374 : +STR_0375 : +STR_0376 : +STR_0377 : +STR_0378 : +STR_0379 : +STR_0380 : +STR_0381 : +STR_0382 : +STR_0383 : +STR_0384 : +STR_0385 : +STR_0386 : +STR_0387 : +STR_0388 : +STR_0389 : +STR_0390 : +STR_0391 : +STR_0392 : +STR_0393 : +STR_0394 : +STR_0395 : +STR_0396 : +STR_0397 : +STR_0398 : +STR_0399 : +STR_0400 : +STR_0401 : +STR_0402 : +STR_0403 : +STR_0404 : +STR_0405 : +STR_0406 : +STR_0407 : +STR_0408 : +STR_0409 : +STR_0410 : +STR_0411 : +STR_0412 : +STR_0413 : +STR_0414 : +STR_0415 : +STR_0416 : +STR_0417 : +STR_0418 : +STR_0419 : +STR_0420 : +STR_0421 : +STR_0422 : +STR_0423 : +STR_0424 : +STR_0425 : +STR_0426 : +STR_0427 : +STR_0428 : +STR_0429 : +STR_0430 : +STR_0431 : +STR_0432 : +STR_0433 : +STR_0434 : +STR_0435 : +STR_0436 : +STR_0437 : +STR_0438 : +STR_0439 : +STR_0440 : +STR_0441 : +STR_0442 : +STR_0443 : +STR_0444 : +STR_0445 : +STR_0446 : +STR_0447 : +STR_0448 : +STR_0449 : +STR_0450 : +STR_0451 : +STR_0452 : +STR_0453 : +STR_0454 : +STR_0455 : +STR_0456 : +STR_0457 : +STR_0458 : +STR_0459 : +STR_0460 : +STR_0461 : +STR_0462 : +STR_0463 : +STR_0464 : +STR_0465 : +STR_0466 : +STR_0467 : +STR_0468 : +STR_0469 : +STR_0470 : +STR_0471 : +STR_0472 : +STR_0473 : +STR_0474 : +STR_0475 : +STR_0476 : +STR_0477 : +STR_0478 : +STR_0479 : +STR_0480 : +STR_0481 : +STR_0482 : +STR_0483 : +STR_0484 : +STR_0485 : +STR_0486 : +STR_0487 : +STR_0488 : +STR_0489 : +STR_0490 : +STR_0491 : +STR_0492 : +STR_0493 : +STR_0494 : +STR_0495 : +STR_0496 : +STR_0497 : +STR_0498 : +STR_0499 : +STR_0500 : +STR_0501 : +STR_0502 : +STR_0503 : +STR_0504 : +STR_0505 : +STR_0506 : +STR_0507 : +STR_0508 : +STR_0509 : +STR_0510 : +STR_0511 : +STR_0512 : +STR_0513 : +STR_0514 :Hängande tåg under banan svingar ut åt sidan i svängar +STR_0515 : +STR_0516 :En snäll berg- och dalbana för de som inte har mod nog att utmana större åkturer +STR_0517 :Passagerare åker i miniatyrtåg på en smal tågräls +STR_0518 :Passagerare åker i elektriska tåg på en balkbana +STR_0519 :Passagerare åker i små vagnar som hänger under en enkelspårig bana, fritt svingande från sida till sida i svängar +STR_0520 : +STR_0521 : +STR_0522 : +STR_0523 :Passagerare åker sakta i motoriserade fordon på en spår-baserad väg +STR_0524 : +STR_0525 : +STR_0526 : +STR_0527 :En mjuk berg- och dalbana byggd av stål som kan göra vertikala loopar +STR_0528 : +STR_0529 : +STR_0530 :Vagnar hänger från en stålkabel som kör kontinuerligt från ena sidan åkturen till den andra, och sedan tillbaka igen +STR_0531 : +STR_0532 : +STR_0533 : +STR_0534 : +STR_0535 : +STR_0536 : +STR_0537 : +STR_0538 : +STR_0539 : +STR_0540 : +STR_0541 : +STR_0542 : +STR_0543 : +STR_0544 : +STR_0545 : +STR_0546 : +STR_0547 : +STR_0548 : +STR_0549 : +STR_0550 : +STR_0551 : +STR_0552 : +STR_0553 : +STR_0554 :Vagnen acceleras ut ur stationen på en platt bana med hjälp av linjärmotorer, sen åker den vertikalt uppåt tills gravitationen tar över och vagnen åker tillbaka till stationen +STR_0555 : +STR_0556 : +STR_0557 : +STR_0558 : +STR_0559 : +STR_0560 : +STR_0561 : +STR_0562 : +STR_0563 :Sittandes i bekväma vagnar njuter passagerare av enorma nedförsbackar och spännande svängar, samt mycket tid flygandes över topparna +STR_0564 :Den här berg- och dalbanan i trä är snabb, tuff, högljudd, och ger en känsla av att tappa kontrollen. Dessutom spenderar man mycket tid flygandes över topparna +STR_0565 :En enkel berg- och dalbana i trä som bara har snälla backar och svängar. Vagnarna hålls på banan med sidofriktion på hjulen och gravitation +STR_0566 :Individuella vagnar åker runt i en tät sicksack-bana med skarpa svängar och korta branta nedförsbackar +STR_0567 :Passagerare sitter i säten på varsin sida av banan och vänds upp och ner medans de åker i branta fall och olika inversioner +STR_0568 : +STR_0569 :Hängandes i speciella selar får passagerare känna på känslan av att flyga runt i luften +STR_0570 : +STR_0571 : +STR_0572 : +STR_0573 : +STR_0574 : +STR_0575 :Motoriserade tåg som hänger från en enkelspårig bana tranporterar folk runt om i parken +STR_0576 : +STR_0577 : +STR_0578 :Vagnar åker runt en bana omgiven av ringar utför branta nedförsbackar och skruvar +STR_0579 : +STR_0580 : +STR_0581 : +STR_0582 : +STR_0583 : +STR_0584 : +STR_0585 : +STR_0586 :Båtformade vagnar åker på berg- och dalbanespår med snurriga svängar och branta nedförsbackar, men plumsar då och då ner i lugna vattensektioner +STR_0587 : +STR_0588 : +STR_0589 : +STR_0590 : +STR_0591 : +STR_0592 : +STR_0593 : +STR_0594 : +STR_0595 : +STR_0596 : +STR_0597 : +STR_0598 : +STR_0599 :En kompakt berg- och dalbana med individuella vagnar och mjuka snurrade nedförsbackar +STR_0600 : +STR_0601 : +STR_0602 : +STR_0603 :Gäst {INT32} +STR_0604 :Gäst {INT32} +STR_0605 :Gäst {INT32} +STR_0606 :Gäst {INT32} +STR_0607 :Gäst {INT32} +STR_0608 :Gäst {INT32} +STR_0609 :Gäst {INT32} +STR_0610 :Gäst {INT32} +STR_0611 :Gäst {INT32} +STR_0612 :Gäst {INT32} +STR_0613 :Gäst {INT32} +STR_0614 :Gäst {INT32} +STR_0615 :Gäst {INT32} +STR_0616 :Gäst {INT32} +STR_0617 :Gäst {INT32} +STR_0618 :Gäst {INT32} +STR_0619 :Gäst {INT32} +STR_0620 :Gäst {INT32} +STR_0621 :Gäst {INT32} +STR_0622 :Gäst {INT32} +STR_0623 :Gäst {INT32} +STR_0624 :Gäst {INT32} +STR_0625 :Gäst {INT32} +STR_0626 :Gäst {INT32} +STR_0627 :Gäst {INT32} +STR_0628 :Gäst {INT32} +STR_0629 :Gäst {INT32} +STR_0630 :Gäst {INT32} +STR_0631 :Gäst {INT32} +STR_0632 :Gäst {INT32} +STR_0633 :Gäst {INT32} +STR_0634 :Gäst {INT32} +STR_0635 :Gäst {INT32} +STR_0636 :Gäst {INT32} +STR_0637 :Gäst {INT32} +STR_0638 :Gäst {INT32} +STR_0639 :Gäst {INT32} +STR_0640 :Gäst {INT32} +STR_0641 :Gäst {INT32} +STR_0642 :Gäst {INT32} +STR_0643 :Gäst {INT32} +STR_0644 :Gäst {INT32} +STR_0645 :Gäst {INT32} +STR_0646 :Gäst {INT32} +STR_0647 :Gäst {INT32} +STR_0648 :Gäst {INT32} +STR_0649 :Gäst {INT32} +STR_0650 :Gäst {INT32} +STR_0651 :Gäst {INT32} +STR_0652 :Gäst {INT32} +STR_0653 :Gäst {INT32} +STR_0654 :Gäst {INT32} +STR_0655 :Gäst {INT32} +STR_0656 :Gäst {INT32} +STR_0657 :Gäst {INT32} +STR_0658 :Gäst {INT32} +STR_0659 :Gäst {INT32} +STR_0660 :Gäst {INT32} +STR_0661 :Gäst {INT32} +STR_0662 :Gäst {INT32} +STR_0663 :Gäst {INT32} +STR_0664 :Gäst {INT32} +STR_0665 :Gäst {INT32} +STR_0666 :Gäst {INT32} +STR_0667 :Gäst {INT32} +STR_0668 :Gäst {INT32} +STR_0669 :Gäst {INT32} +STR_0670 :Gäst {INT32} +STR_0671 :Gäst {INT32} +STR_0672 :Gäst {INT32} +STR_0673 :Gäst {INT32} +STR_0674 :Gäst {INT32} +STR_0675 :Gäst {INT32} +STR_0676 :Gäst {INT32} +STR_0677 :Gäst {INT32} +STR_0678 :Gäst {INT32} +STR_0679 :Gäst {INT32} +STR_0680 :Gäst {INT32} +STR_0681 :Gäst {INT32} +STR_0682 :Gäst {INT32} +STR_0683 :Gäst {INT32} +STR_0684 :Gäst {INT32} +STR_0685 :Gäst {INT32} +STR_0686 :Gäst {INT32} +STR_0687 :Gäst {INT32} +STR_0688 :Gäst {INT32} +STR_0689 :Gäst {INT32} +STR_0690 :Gäst {INT32} +STR_0691 :Gäst {INT32} +STR_0692 :Gäst {INT32} +STR_0693 :Gäst {INT32} +STR_0694 :Gäst {INT32} +STR_0695 :Gäst {INT32} +STR_0696 :Gäst {INT32} +STR_0697 :Gäst {INT32} +STR_0698 :Gäst {INT32} +STR_0699 :Gäst {INT32} +STR_0700 :Gäst {INT32} +STR_0701 :Gäst {INT32} +STR_0702 :Gäst {INT32} +STR_0703 :Gäst {INT32} +STR_0704 :Gäst {INT32} +STR_0705 :Gäst {INT32} +STR_0706 :Gäst {INT32} +STR_0707 :Gäst {INT32} +STR_0708 :Gäst {INT32} +STR_0709 :Gäst {INT32} +STR_0710 :Gäst {INT32} +STR_0711 :Gäst {INT32} +STR_0712 :Gäst {INT32} +STR_0713 :Gäst {INT32} +STR_0714 :Gäst {INT32} +STR_0715 :Gäst {INT32} +STR_0716 :Gäst {INT32} +STR_0717 :Gäst {INT32} +STR_0718 :Gäst {INT32} +STR_0719 :Gäst {INT32} +STR_0720 :Gäst {INT32} +STR_0721 :Gäst {INT32} +STR_0722 :Gäst {INT32} +STR_0723 :Gäst {INT32} +STR_0724 :Gäst {INT32} +STR_0725 :Gäst {INT32} +STR_0726 :Gäst {INT32} +STR_0727 :Gäst {INT32} +STR_0728 :Gäst {INT32} +STR_0729 :Gäst {INT32} +STR_0730 :Gäst {INT32} +STR_0731 :Gäst {INT32} +STR_0732 :Gäst {INT32} +STR_0733 :Gäst {INT32} +STR_0734 :Gäst {INT32} +STR_0735 :Gäst {INT32} +STR_0736 :Gäst {INT32} +STR_0737 :Gäst {INT32} +STR_0738 :Gäst {INT32} +STR_0739 :Gäst {INT32} +STR_0740 :Gäst {INT32} +STR_0741 :Gäst {INT32} +STR_0742 :Gäst {INT32} +STR_0743 :Gäst {INT32} +STR_0744 :Gäst {INT32} +STR_0745 :Gäst {INT32} +STR_0746 :Gäst {INT32} +STR_0747 :Gäst {INT32} +STR_0748 :Gäst {INT32} +STR_0749 :Gäst {INT32} +STR_0750 :Gäst {INT32} +STR_0751 :Gäst {INT32} +STR_0752 :Gäst {INT32} +STR_0753 :Gäst {INT32} +STR_0754 :Gäst {INT32} +STR_0755 :Gäst {INT32} +STR_0756 :Gäst {INT32} +STR_0757 :Gäst {INT32} +STR_0758 :Gäst {INT32} +STR_0759 :Gäst {INT32} +STR_0760 :Gäst {INT32} +STR_0761 :Gäst {INT32} +STR_0762 :Gäst {INT32} +STR_0763 :Gäst {INT32} +STR_0764 :Gäst {INT32} +STR_0765 :Gäst {INT32} +STR_0766 :Gäst {INT32} +STR_0767 :Gäst {INT32} +STR_0768 :Vaktmästare {INT32} +STR_0769 :Mekaniker {INT32} +STR_0770 :Säkerhetsvakt {INT32} +STR_0771 :Underhållare {INT32} +STR_0772 :Namnlös park{POP16}{POP16} +STR_0773 :Namnlös park{POP16}{POP16} +STR_0774 :Namnlös park{POP16}{POP16} +STR_0775 :Namnlös park{POP16}{POP16} +STR_0776 :Namnlös park{POP16}{POP16} +STR_0777 :Namnlös park{POP16}{POP16} +STR_0778 :Skylt +STR_0779 :1 +STR_0780 :2 +STR_0781 :3 +STR_0782 :4 +STR_0783 :5 +STR_0784 :6 +STR_0785 :7 +STR_0786 :8 +STR_0787 :9 +STR_0788 :10 +STR_0789 :11 +STR_0790 :12 +STR_0791 :13 +STR_0792 :14 +STR_0793 :15 +STR_0794 :16 +STR_0795 :17 +STR_0796 :18 +STR_0797 :19 +STR_0798 :20 +STR_0799 :21 +STR_0800 :22 +STR_0801 :23 +STR_0802 :24 +STR_0803 :25 +STR_0804 :26 +STR_0805 :27 +STR_0806 :28 +STR_0807 :29 +STR_0808 :30 +STR_0809 :31 +STR_0810 :Jan +STR_0811 :Feb +STR_0812 :Mar +STR_0813 :Apr +STR_0814 :Maj +STR_0815 :Jun +STR_0816 :Jul +STR_0817 :Aug +STR_0818 :Sep +STR_0819 :Okt +STR_0820 :Nov +STR_0821 :Dec +STR_0822 :Kan inte komma åt grafikfilen +STR_0823 :Saknad eller otillgänglig datafil +STR_0824 :{BLACK}{CROSS} +STR_0825 :Det valda namnet används redan +STR_0826 :För många namn är definierade +STR_0827 :Inte nog med pengar - det behövs {CURRENCY2DP} +STR_0828 :{SMALLFONT}{BLACK}Stäng fönster +STR_0829 :{SMALLFONT}{BLACK}Fönstertitel - Dra för att flytta fönstret +STR_0830 :{SMALLFONT}{BLACK}Zooma in +STR_0831 :{SMALLFONT}{BLACK}Zooma ut +STR_0832 :{SMALLFONT}{BLACK}Rotera vyn 90{DEGREE} medurs +STR_0833 :{SMALLFONT}{BLACK}Pausa spelet +STR_0834 :{SMALLFONT}{BLACK}Inställningar +STR_0835 :Spelet kunde inte starta +STR_0836 :Kan inte starta spelet minimerat +STR_0837 :Kan inte initiera grafiksystemet +STR_0838 :CD-nyckeln {INT32} är inte giltig för RollerCoaster Tycoon 2!{WINDOW_COLOUR_1}{WINDOW_COLOUR_1}Var god avinstallera RollerCoaster Tycoon 2% och återinstallera med rätt CD-nyckel +STR_0839 :{UINT16} x {UINT16} +STR_0840 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{UINT16} x {UINT16} +STR_0841 :Skrivbordsfönster +STR_0842 :640x480 helskärm +STR_0843 :800x600 helskärm +STR_0844 :1024x768 helskärm +STR_0845 :1152x864 helskärm +STR_0846 :1280x1024 helskärm +STR_0847 :Om 'RollerCoaster Tycoon 2' +STR_0848 :RollerCoaster Tycoon 2 +STR_0849 :{WINDOW_COLOUR_2}Version 2.01.028 +STR_0850 :{WINDOW_COLOUR_2}Copyright {COPYRIGHT} 2002 Chris Sawyer, alla rättigheter förbehålls +STR_0851 :{WINDOW_COLOUR_2}Designat och programmerat av Chris Sawyer +STR_0852 :{WINDOW_COLOUR_2}Grafik av Simon Foster +STR_0853 :{WINDOW_COLOUR_2}Ljud och musik av Allister Brimble +STR_0854 :{WINDOW_COLOUR_2}Ytterligare ljud inspelade av David Ellis +STR_0855 :{WINDOW_COLOUR_2}Representation av Jacqui Lyons från Marjacq Ltd. +STR_0856 :{WINDOW_COLOUR_2}Tack till:- +STR_0857 :{WINDOW_COLOUR_2}Peter James Adcock, Joe Booth, och John Wardley +STR_0858 :{WINDOW_COLOUR_2} +STR_0859 :{WINDOW_COLOUR_2} +STR_0860 :{WINDOW_COLOUR_2} +STR_0861 : +STR_0862 : +STR_0863 : +STR_0864 : +STR_0865 :{STRINGID} +STR_0866 :{POP16}{STRINGID} +STR_0867 :{POP16}{POP16}{STRINGID} +STR_0868 :{POP16}{POP16}{POP16}{STRINGID} +STR_0869 :{POP16}{POP16}{POP16}{POP16}{STRINGID} +STR_0870 :{POP16}{POP16}{POP16}{POP16}{POP16}{STRINGID} +STR_0871 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{STRINGID} +STR_0872 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{STRINGID} +STR_0873 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{STRINGID} +STR_0874 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{STRINGID} +STR_0875 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{STRINGID} +STR_0876 :{BLACK}{DOWN} +STR_0877 :För lågt ! +STR_0878 :För högt ! +STR_0879 :Kan inte sänka landnivån här... +STR_0880 :Kan inte höja landnivån här... +STR_0881 :Ett objekt är i vägen +STR_0882 :Spara Spel +STR_0883 :Ladda Spel +STR_0884 :Ladda Landskap +STR_0885 :Spara Landskap +STR_0886 :Avsluta Spel +STR_0887 :Avsluta Scenarioskaparen +STR_0888 :Avsluta Berg- och Dalbanabyggaren +STR_0889 :Avsluta Spårredigeraren +STR_0890 :SCR{COMMA16}.BMP +STR_0891 :Skärmdump +STR_0892 :Skärmdumpen sparades som '{STRINGID}' +STR_0893 :Skärmdumpen misslyckades! +STR_0894 :Landskapens minnesområde är fullt ! +STR_0895 :Kan inte bygga både ovan och under jord samtidigt +STR_0896 :{POP16}{POP16}{STRINGID} Konstruktion +STR_0897 :Riktning +STR_0898 :{SMALLFONT}{BLACK}Vänsterkurva +STR_0899 :{SMALLFONT}{BLACK}Högerkurva +STR_0900 :{SMALLFONT}{BLACK}Vänsterkurva (liten radie) +STR_0901 :{SMALLFONT}{BLACK}Högerkurva (liten radie) +STR_0902 :{SMALLFONT}{BLACK}Vänsterkurva (väldigt liten radie) +STR_0903 :{SMALLFONT}{BLACK}Högerkurva (väldigt liten radie) +STR_0904 :{SMALLFONT}{BLACK}Vänsterkurva (stor radie) +STR_0905 :{SMALLFONT}{BLACK}Högerkurva (stor radie) +STR_0906 :{SMALLFONT}{BLACK}Rakt +STR_0907 :Sluttning +STR_0908 :Lutning +STR_0909 :Säteslutning +STR_0910 :{SMALLFONT}{BLACK}Lutning för Vänsterkurva +STR_0911 :{SMALLFONT}{BLACK}Lutning för Högerkurva +STR_0912 :{SMALLFONT}{BLACK}Ingen lutning +STR_0913 :{SMALLFONT}{BLACK}Tidigare sektion +STR_0914 :{SMALLFONT}{BLACK}Nästa sektion +STR_0915 :{SMALLFONT}{BLACK}Bygg den valda sektionen +STR_0916 :{SMALLFONT}{BLACK}Ta bort den valda sektionen +STR_0917 :{SMALLFONT}{BLACK}Vertikalt nedåt +STR_0918 :{SMALLFONT}{BLACK}Brant nedförsbacke +STR_0919 :{SMALLFONT}{BLACK}Nedförsbacke +STR_0920 :{SMALLFONT}{BLACK}Platt +STR_0921 :{SMALLFONT}{BLACK}Uppförsbacke +STR_0922 :{SMALLFONT}{BLACK}Brant uppförsbacke +STR_0923 :{SMALLFONT}{BLACK}Vertikalt uppåt +STR_0924 :{SMALLFONT}{BLACK}Helix nedåt +STR_0925 :{SMALLFONT}{BLACK}Helix uppåt +STR_0926 :Kan inte ta bort det här... +STR_0927 :Kan inte bygga här... +STR_0928 :{SMALLFONT}{BLACK}Lyftkedjor, för att dra upp vagnar för backar +STR_0929 :'S'-Böj (vänster) +STR_0930 :'S'-Böj (höger) +STR_0931 :Vertikal Loop (vänster) +STR_0932 :Vertikal Loop (höger) +STR_0933 :Höj eller sänk landnivån först +STR_0934 :En åkturer ingång är i vägen +STR_0935 :En åkturer utgång är i vägen +STR_0936 :Parkentrén är i vägen +STR_0937 :{SMALLFONT}{BLACK}Vyinställningar +STR_0938 :{SMALLFONT}{BLACK}Justera landnivån och sluttning +STR_0939 :Underjordsvy +STR_0940 :Dölj terräng +STR_0941 :Dölj vertikala sidor +STR_0942 :Genomskinliga Åkturer +STR_0943 :Genomskinliga Dekorationer +STR_0944 :Spara +STR_0945 :Spara inte +STR_0946 :Avbryt +STR_0947 :Spara innan du laddar ? +STR_0948 :Spara innan du avslutar ? +STR_0949 :Spara innan du avslutar ? +STR_0950 :Ladda Spel +STR_0951 :Avsluta Spel +STR_0952 :Avsluta Spel +STR_0953 :Ladda Landskap +STR_0954 : +STR_0955 :{SMALLFONT}{BLACK}Välj säteslutningen för den här sektionen +STR_0956 :-180{DEGREE} +STR_0957 :-135{DEGREE} +STR_0958 :-90{DEGREE} +STR_0959 :-45{DEGREE} +STR_0960 :0{DEGREE} +STR_0961 :+45{DEGREE} +STR_0962 :+90{DEGREE} +STR_0963 :+135{DEGREE} +STR_0964 :+180{DEGREE} +STR_0965 :+225{DEGREE} +STR_0966 :+270{DEGREE} +STR_0967 :+315{DEGREE} +STR_0968 :+360{DEGREE} +STR_0969 :+405{DEGREE} +STR_0970 :+450{DEGREE} +STR_0971 :+495{DEGREE} +STR_0972 :Avbryt +STR_0973 :OK +STR_0974 :Åkturer +STR_0975 :Affärer och Stånd +STR_0976 :Toaletter och Informationskiosker +STR_0977 :Nya Transportåkturer +STR_0978 :Nya Lugna Åkturer +STR_0979 :Nya Berg- och Dalbanor +STR_0980 :Nya Spännande Åkturer +STR_0981 :Nya Vattenåkturer +STR_0982 :Nya Affärer & Stånd +STR_0983 :Forskning & Utveckling +STR_0984 :{WINDOW_COLOUR_2}{UP}{BLACK} {CURRENCY2DP} +STR_0985 :{WINDOW_COLOUR_2}{DOWN}{BLACK} {CURRENCY2DP} +STR_0986 :{BLACK}{CURRENCY2DP} +STR_0987 :För många åkturer/attraktioner +STR_0988 :Kan inte skapa ny åktur/attraktion... +STR_0989 :{STRINGID} +STR_0990 :{SMALLFONT}{BLACK}Konstruktion +STR_0991 :Stationsplattform +STR_0992 :{SMALLFONT}{BLACK}Riv hela åkturen/attraktionen +STR_0993 :Riv åktur/attraktion +STR_0994 :Riv +STR_0995 :{WINDOW_COLOUR_1}Är du säker på att du vill riva {STRINGID} fullständigt? +STR_0996 :Översiktsvy +STR_0997 :{SMALLFONT}{BLACK}Visa markering +STR_0998 :Inga fler stationer är tillåtna för den här åkturen +STR_0999 :En stationsplattform krävs +STR_1000 :Banan är inte ihopkopplad +STR_1001 :Banan är ej lämplig för vagntypen +STR_1002 :Kan inte öppna {POP16}{POP16}{POP16}{STRINGID}... +STR_1003 :Kan inte testa {POP16}{POP16}{POP16}{STRINGID}... +STR_1004 :Kan inte stänga {POP16}{POP16}{POP16}{STRINGID}... +STR_1005 :Kan inte påbörja byggnadsarbetet på {POP16}{POP16}{POP16}{STRINGID}... +STR_1006 :Måste vara stängd först +STR_1007 :Kan inte skapa nog vagnar +STR_1008 :{SMALLFONT}{BLACK}Öppna, stäng eller testa åktur/attraktion +STR_1009 :{SMALLFONT}{BLACK}Öppna eller stäng alla åkturer/attraktioner +STR_1010 :{SMALLFONT}{BLACK}Öppna eller stäng parken +STR_1011 :Stäng alla +STR_1012 :Öppna alla +STR_1013 :Stäng parken +STR_1014 :Öppna parken +STR_1015 :Åkturen kan inte köras med fler än en stationsplattform i detta läge +STR_1016 :Åkturen kan inte köras med mindre än två stationer i detta läge +STR_1017 :Kan inte byta körläge... +STR_1018 :Kan inte göra förändringar... +STR_1019 :Kan inte göra förändringar... +STR_1020 :Kan inte göra förändringar... +STR_1021 :{POP16}{POP16}{POP16}{POP16}{STRINGID} +STR_1022 :{POP16}{POP16}{POP16}{COMMA16} vagn per tåg +STR_1023 :{POP16}{POP16}{POP16}{COMMA16} vagnar per tåg +STR_1024 :{COMMA16} vagn per tåg +STR_1025 :{COMMA16} vagnar per tåg +STR_1026 :Stationsplattformen är för lång! +STR_1027 :{SMALLFONT}{BLACK}Hitta detta på huvudvyn +STR_1028 :Utanför kartan! +STR_1029 :Kan inte bygga både ovan och under vatten samtidigt! +STR_1030 :Kan endast bygga detta under vatten! +STR_1031 :Kan inte bygga detta under vatten! +STR_1032 :Kan endast bygga detta på vatten! +STR_1033 :Kan endast bygga detta ovanför land! +STR_1034 :Kan endast bygga detta på land! +STR_1035 :Lokala myndigheter tillåter inte konstruktion ovanför trähöjd! +STR_1036 :Ladda Spel +STR_1037 :Ladda Landskap +STR_1038 :Omvandla sparat spel till scenario +STR_1039 :Installera ny bandesign +STR_1040 :Spara Spel +STR_1041 :Spara Scenario +STR_1042 :Spara Landskap +STR_1043 :RollerCoaster Tycoon 2 Sparat Spel +STR_1044 :RollerCoaster Tycoon 2 Sparat Scenario +STR_1045 :RollerCoaster Tycoon 2 Sparat Landskap +STR_1046 :RollerCoaster Tycoon 2 Sparad Bandesign +STR_1047 :Misslyckades med att spara spelet! +STR_1048 :Misslyckades med att spara scenario! +STR_1049 :Misslyckades med att spara landskap! +STR_1050 :Misslyckades att ladda...{NEWLINE}Filen innehåller ogiltig data! +STR_1051 :Dölj Stödpelare +STR_1052 :Dölj Besökare +STR_1053 :{SMALLFONT}{BLACK}Åkturer/attraktioner i parken +STR_1054 :{SMALLFONT}{BLACK}Namnge åktur/attraktion +STR_1055 :{SMALLFONT}{BLACK}Namnge person +STR_1056 :{SMALLFONT}{BLACK}Namnge anställd +STR_1057 :Åkturens/attraktionens namn +STR_1058 :Skriv in ett nytt namn för den här åkturen/attraktionen:- +STR_1059 :Kan inte namnge åktur/attraktion... +STR_1060 :Ogiltigt åktur/attraktionsnamn +STR_1061 :Normalt läge +STR_1062 :Kontinuerligt banläge +#TODO +STR_1063 :Reverse-Incline launched shuttle mode +STR_1064 :Accelererad start +STR_1065 :Pendlarläge +STR_1066 :Uthyrning +STR_1067 :Uppskjut +STR_1068 :Roterande hiss +STR_1069 :Station till station +STR_1070 :En åktur per biljett +STR_1071 :Oändligt med åkturer per biljett +STR_1072 :Labyrint +STR_1073 :Rallyläge +STR_1074 :Krockbilar +STR_1075 :Svängläge +STR_1076 :Stånd +STR_1077 :Rotationsläge +STR_1078 :Rotation framåt +STR_1079 :Rotation bakåt +STR_1080 :Film: {ENDQUOTES}Glödande Glajjor{ENDQUOTES} +STR_1081 :3D-film: {ENDQUOTES}Mussvansar{ENDQUOTES} +STR_1082 :Rymdringar +STR_1083 :Nybörjarläge +STR_1084 :LIM-accelererad start +STR_1085 :Film: {ENDQUOTES}Spänning i Farten{ENDQUOTES} +STR_1086 :3D film: {ENDQUOTES}Stormjägarna{ENDQUOTES} +STR_1087 :3D film: {ENDQUOTES}Rymdrädarna{ENDQUOTES} +STR_1088 :Intensivt läge +STR_1089 :Berserkläge +STR_1090 :Spökhuset +STR_1091 :Circusvisning +STR_1092 :Nedåtriktad start +STR_1093 :Snea huset +STR_1094 :Fritt fall +STR_1095 :Blockavdelat kontinuerligt banläge +STR_1096 :Motoriserad start +STR_1097 :Blockavdelad motoriserad start +STR_1098 :Rör sig mot slutet av {POP16}{STRINGID} +STR_1099 :Väntar på passagerare vid {POP16}{STRINGID} +STR_1100 :Väntar på avgång vid {POP16}{STRINGID} +STR_1101 :Avgår {POP16}{STRINGID} +STR_1102 :Åker i {VELOCITY} +STR_1103 :Anländer vid {POP16}{STRINGID} +STR_1104 :Släpper av passagerare vid {POP16}{STRINGID} +STR_1105 :Åker i {VELOCITY} +STR_1106 :Kraschar! +STR_1107 :Kraschat! +STR_1108 :Åker i {VELOCITY} +STR_1109 :Svingar +STR_1110 :Roterar +STR_1111 :Roterar +STR_1112 :Pågår +STR_1113 :Showing film +STR_1114 :Rotating +STR_1115 :Pågår +STR_1116 :Pågår +STR_1117 :Circusshow pågår +STR_1118 :Pågår +STR_1119 :Väntar på linbanevagn +STR_1120 :Åker i {VELOCITY} +STR_1121 :Stoppar +STR_1122 :Väntar på passagerare +STR_1123 :Väntar på att starta +STR_1124 :Startar +STR_1125 :Pågår +STR_1126 :Stoppar +STR_1127 :Släpper av passagerare +STR_1128 :Stoppad av bromsblock +STR_1129 :Alla fordon i samma färg +STR_1130 :Olika färg per {STRINGID} +STR_1131 :Olika färg per fordon +STR_1132 :Fordon {POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1133 :Fordon {POP16}{COMMA16} +STR_1134 :{POP16}{POP16}{POP16}{POP16}{POP16}{STRINGID} {COMMA16} +STR_1135 :{STRINGID} {COMMA16} +STR_1136 :{SMALLFONT}{BLACK}Välj huvudfärg +STR_1137 :{SMALLFONT}{BLACK}Välj andra färg +STR_1138 :{SMALLFONT}{BLACK}Välj tredje färg +STR_1139 :{SMALLFONT}{BLACK}Välj färg för stödpelare +STR_1140 :{SMALLFONT}{BLACK}Välj färgpalett för fordon +STR_1141 :{SMALLFONT}{BLACK}Välj vilket fordon/tåg som ska modifieras +STR_1142 :{MOVE_X}{SMALLFONT}{STRINGID} +STR_1143 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRINGID} +STR_1144 :Kan inte bygga/flytta ingången för den här åkturen/attraktionen... +STR_1145 :Kan inte bygga/flytta utgången för den här åkturen/attraktionen... +STR_1146 :Ingången är inte byggd +STR_1147 :Utgången är inte byggd +STR_1148 :En kvarts fullt +STR_1149 :Halvfullt +STR_1150 :Trekvarts fullt +STR_1151 :Fullt +STR_1152 :Minst en person +STR_1153 :Höjdmarkeringar på Åkturer +STR_1154 :Höjdmarkeringar på Land +STR_1155 :Höjdmarkeringar på Gångvägar +STR_1156 :{MOVE_X}{SMALLFONT}{STRINGID} +STR_1157 :{TICK}{MOVE_X}{SMALLFONT}{STRINGID} +STR_1158 :Kan inte ta bort detta... +STR_1159 :{SMALLFONT}{BLACK}Placera dekorationer, trädgårdar, och andra tillbehör +STR_1160 :{SMALLFONT}{BLACK}Skapa/justera sjöar och vatten +STR_1161 :Kan inte placera detta här... +STR_1162 :{OUTLINE}{TOPAZ}{STRINGID} +STR_1163 :{STRINGID}{NEWLINE}(Höger-Click to Modify) +STR_1164 :{STRINGID}{NEWLINE}(Höger-Click to Remove) +STR_1165 :{STRINGID} - {STRINGID} {COMMA16} +STR_1166 :Kan inte sänka vattennivån... +STR_1167 :Kan inte höja vattennivån... +STR_1168 :Inställningar +STR_1169 :(Inga) +STR_1170 :{STRING} +STR_1171 :{RED}Closed - - +STR_1172 :{YELLOW}{STRINGID} - - +STR_1173 :{SMALLFONT}{BLACK}Bygg gångvägar och köer +STR_1174 :En skylt är i vägen +STR_1175 :Kan inte bygga på en sluttande gångväg +STR_1176 :Kan inte bygga gångväg här... +STR_1177 :Kan inte ta bort gångvägen här... +STR_1178 :Markens sluttning är inte lämplig +STR_1179 :Gånvägen är i vägen +STR_1180 :Kan inte bygga det här under vatten! +STR_1181 :Gångvägar +STR_1182 :Sort +STR_1183 :Riktning +STR_1184 :Sluttning +STR_1185 :{SMALLFONT}{BLACK}Riktning +STR_1186 :{SMALLFONT}{BLACK}Sluttning nedåt +STR_1187 :{SMALLFONT}{BLACK}Platt +STR_1188 :{SMALLFONT}{BLACK}Sluttning uppåt +STR_1189 :{SMALLFONT}{BLACK}Bygg den valda gångvägssektionen +STR_1190 :{SMALLFONT}{BLACK}Ta bort gångvägssektion +STR_1191 :{BLACK}{STRINGID} +STR_1192 :{OUTLINE}{RED}{STRINGID} +STR_1193 :{WINDOW_COLOUR_2}{STRINGID} +STR_1194 :Stängd +STR_1195 :Testkörning +STR_1196 :Öppen +STR_1197 :Trasig +STR_1198 :Kraschad! +STR_1199 :{COMMA16} person på åkturen +STR_1200 :{COMMA16} personer på åkturen +STR_1201 :Ingen i kön +STR_1202 :1 person i kön +STR_1203 :{COMMA16} personer i kön +STR_1204 :{COMMA16} minut kötid +STR_1205 :{COMMA16} minuter kötid +STR_1206 :{WINDOW_COLOUR_2}Vänta på: +STR_1207 :{WINDOW_COLOUR_2}Lämna om ett annat tåg anländer till stationen +STR_1208 :{WINDOW_COLOUR_2}Lämna om en annan båt lägger an vid stationen +STR_1209 :{SMALLFONT}{BLACK}Välj om tåget ska invänta passagerare innan avgång +STR_1210 :{SMALLFONT}{BLACK}Välj om avgång ska ske då ett annat fordon anländer +STR_1211 :{WINDOW_COLOUR_2}Minsta väntetid: +STR_1212 :{WINDOW_COLOUR_2}Högsta väntetid: +STR_1213 :{SMALLFONT}{BLACK}Välj minste väntetid innan avgång +STR_1214 :{SMALLFONT}{BLACK}Välj högsta väntetid innan avgång +STR_1215 :{WINDOW_COLOUR_2}Synkronisera med närliggande stationer +STR_1216 :{SMALLFONT}{BLACK}Välj om avgången ska synkroniseras med alla närliggande stationer (för 'rally') +STR_1217 :{COMMA16} sekunder +STR_1218 :{BLACK}{SMALLUP} +STR_1219 :{BLACK}{SMALLDOWN} +STR_1220 :Endast utgång +STR_1221 :Ingen ingång +STR_1222 :Ingen utgång +STR_1223 :{SMALLFONT}{BLACK}Transportåkturer +STR_1224 :{SMALLFONT}{BLACK}Lugna åkturer +STR_1225 :{SMALLFONT}{BLACK}Berg- och dalbanor +STR_1226 :{SMALLFONT}{BLACK}Spännande åkturer +STR_1227 :{SMALLFONT}{BLACK}Vattenåkturer +STR_1228 :{SMALLFONT}{BLACK}Affärer & stånd +STR_1229 :tåg +STR_1230 :tåg +STR_1231 :Tåg +STR_1232 :Tåg +STR_1233 :{COMMA16} tåg +STR_1234 :{COMMA16} tåg +STR_1235 :Tåg {COMMA16} +STR_1236 :båt +STR_1237 :båtar +STR_1238 :Båt +STR_1239 :Båtar +STR_1240 :{COMMA16} båt +STR_1241 :{COMMA16} båtar +STR_1242 :Båt {COMMA16} +STR_1243 :spår +STR_1244 :spår +STR_1245 :Spår +STR_1246 :Spår +STR_1247 :{COMMA16} spår +STR_1248 :{COMMA16} spår +STR_1249 :Spår {COMMA16} +STR_1250 :brygga +STR_1251 :bryggor +STR_1252 :Brygga +STR_1253 :Bryggor +STR_1254 :{COMMA16} brygga +STR_1255 :{COMMA16} bryggor +STR_1256 :Brygga {COMMA16} +STR_1257 :station +STR_1258 :stationer +STR_1259 :Station +STR_1260 :Stationer +STR_1261 :{COMMA16} station +STR_1262 :{COMMA16} stationer +STR_1263 :Station {COMMA16} +STR_1264 :bil +STR_1265 :bilar +STR_1266 :Bil +STR_1267 :Bilar +STR_1268 :{COMMA16} bil +STR_1269 :{COMMA16} bilar +STR_1270 :Bil {COMMA16} +STR_1271 :byggnad +STR_1272 :byggnader +STR_1273 :Byggnad +STR_1274 :Byggnader +STR_1275 :{COMMA16} byggnad +STR_1276 :{COMMA16} byggnader +STR_1277 :Byggnad {COMMA16} +STR_1278 :struktur +STR_1279 :strukturer +STR_1280 :Struktur +STR_1281 :Strukturer +STR_1282 :{COMMA16} struktur +STR_1283 :{COMMA16} strukturer +STR_1284 :Struktur {COMMA16} +STR_1285 :skepp +STR_1286 :skepp +STR_1287 :Skepp +STR_1288 :Skepp +STR_1289 :{COMMA16} skepp +STR_1290 :{COMMA16} skepp +STR_1291 :Skepp {COMMA16} +STR_1292 :kabin +STR_1293 :kabiner +STR_1294 :Kabin +STR_1295 :Kabiner +STR_1296 :{COMMA16} kabin +STR_1297 :{COMMA16} kabiner +STR_1298 :Kabin {COMMA16} +STR_1299 :hjul +STR_1300 :hjul +STR_1301 :Hjul +STR_1302 :Hjul +STR_1303 :{COMMA16} hjul +STR_1304 :{COMMA16} hjul +STR_1305 :Hjul {COMMA16} +STR_1306 :ring +STR_1307 :ringar +STR_1308 :Ring +STR_1309 :Ringar +STR_1310 :{COMMA16} ring +STR_1311 :{COMMA16} ringar +STR_1312 :Ring {COMMA16} +STR_1313 :spelare +STR_1314 :spelare +STR_1315 :Spelare +STR_1316 :Spelare +STR_1317 :{COMMA16} spelare +STR_1318 :{COMMA16} spelare +STR_1319 :Spelare {COMMA16} +STR_1320 :bana +STR_1321 :bana +STR_1322 :Banor +STR_1323 :Banor +STR_1324 :{COMMA16} bana +STR_1325 :{COMMA16} banor +STR_1326 :Bana {COMMA16} +STR_1327 :{SMALLFONT}{BLACK}Rotera objekt 90{DEGREE} +STR_1328 :Platt land krävs +STR_1329 :{WINDOW_COLOUR_2}Starthastighet: +STR_1330 :{SMALLFONT}{BLACK}Maxhastighet när tåget lämnar stationen +STR_1331 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{VELOCITY} +STR_1332 :{VELOCITY} +STR_1333 :{STRINGID} - {STRINGID}{POP16} +STR_1334 :{STRINGID} - {STRINGID} {COMMA16} +STR_1335 :{STRINGID} - Ingång{POP16}{POP16} +STR_1336 :{STRINGID} - Station {POP16}{COMMA16} Ingång +STR_1337 :{STRINGID} - Utgång{POP16}{POP16} +STR_1338 :{STRINGID} - Station {POP16}{COMMA16} Utgång +STR_1339 :{BLACK}Inga testresultat än... +STR_1340 :{WINDOW_COLOUR_2}Maxhastighet: {BLACK}{VELOCITY} +STR_1341 :{WINDOW_COLOUR_2}Åktid: {BLACK}{STRINGID}{STRINGID}{STRINGID}{STRINGID} +STR_1342 :{DURATION} +STR_1343 :{DURATION} / +STR_1344 :{WINDOW_COLOUR_2}Åkturens längd: {BLACK}{STRINGID}{STRINGID}{STRINGID}{STRINGID} +STR_1345 :{LENGTH} +STR_1346 :{LENGTH} / +STR_1347 :{WINDOW_COLOUR_2}Genomsnittshastighet: {BLACK}{VELOCITY} +STR_1348 :{WINDOW_COLOUR_2}Max positiva vertikala G-krafter: {BLACK}{COMMA2DP32}g +STR_1349 :{WINDOW_COLOUR_2}Max positiva vertikala G-krafter: {OUTLINE}{RED}{COMMA2DP32}g +STR_1350 :{WINDOW_COLOUR_2}Max negativa vertikala G-krafter: {BLACK}{COMMA2DP32}g +STR_1351 :{WINDOW_COLOUR_2}Max negativa vertikala G-krafter: {OUTLINE}{RED}{COMMA2DP32}g +STR_1352 :{WINDOW_COLOUR_2}Max laterala G-krafter: {BLACK}{COMMA2DP32}g +STR_1353 :{WINDOW_COLOUR_2}Max laterala G-krafter: {OUTLINE}{RED}{COMMA2DP32}g +STR_1354 :{WINDOW_COLOUR_2}Högsta fallhöjd: {BLACK}{LENGTH} +STR_1355 :{WINDOW_COLOUR_2}Fall: {BLACK}{COMMA16} +STR_1356 :{WINDOW_COLOUR_2}Inversioner: {BLACK}{COMMA16} +STR_1357 :{WINDOW_COLOUR_2}Hål: {BLACK}{COMMA16} +STR_1358 :{WINDOW_COLOUR_2}Total 'flyg'-tid: {BLACK}{COMMA2DP32}secs +STR_1359 :{WINDOW_COLOUR_2}Kötod: {BLACK}{COMMA16} minute +STR_1360 :{WINDOW_COLOUR_2}Kötid: {BLACK}{COMMA16} minutes +STR_1361 :Kan inte ändra hastighet... +STR_1362 :Kan inte ändra starthastighet... +STR_1363 :För högt för stödpelare! +STR_1364 :Stödpelarna kan inte förlängas mer! +STR_1365 :Tvist (vänster) +STR_1366 :Tvist (höger) +STR_1367 :Halvloop +STR_1368 :Halv Korkskruv (vänster) +STR_1369 :Halv Korkskruv (höger) +STR_1370 :Roll (vänster) +STR_1371 :Roll (höger) +STR_1372 :Uppskjutskulle +STR_1373 :Stor Halvloop (vänster) +STR_1374 :Stor Halvloop (höger) +STR_1375 :Övre Vidarekoppling +STR_1376 :Nedre Vidarekoppling +STR_1377 :Heartline-Roll (vänster) +STR_1378 :Heartline-Roll (höger) +STR_1379 :Omvändare (vänster) +STR_1380 :Omvändare (höger) +STR_1381 :Kurvad Uppskjutskulle (vänster) +STR_1382 :Kurvad Uppskjutskulle (höger) +STR_1383 :Kvarts Loop +STR_1384 :{YELLOW}{STRINGID} +STR_1385 :{SMALLFONT}{BLACK}Andra bankonfigurationer +STR_1386 :Speciell... +STR_1387 :Kan inte byta terrängtyp... +STR_1388 :{OUTLINE}{GREEN}+ {CURRENCY} +STR_1389 :{OUTLINE}{RED}- {CURRENCY} +STR_1390 :{CURRENCY2DP} +STR_1391 :{RED}{CURRENCY2DP} +STR_1392 :{SMALLFONT}{BLACK}Åkturs/attraktions-vy +STR_1393 :{SMALLFONT}{BLACK}Fordondetaljer och inställningar +STR_1394 :{SMALLFONT}{BLACK}Operating options +STR_1395 :{SMALLFONT}{BLACK}Underhållsinställningar +STR_1396 :{SMALLFONT}{BLACK}Färginställningar +STR_1397 :{SMALLFONT}{BLACK}Ljud- och musikinställningar +STR_1398 :{SMALLFONT}{BLACK}Mätvärden och testdata +STR_1399 :{SMALLFONT}{BLACK}Grafer +STR_1400 :Ingång +STR_1401 :Utgång +STR_1402 :{SMALLFONT}{BLACK}Bygg eller flytta ingången till åkturen/attraktionen +STR_1403 :{SMALLFONT}{BLACK}Bygg eller flytta utgången till åkturen/attraktionen +STR_1404 :{SMALLFONT}{BLACK}Rotera 90{DEGREE} +STR_1405 :{SMALLFONT}{BLACK}Spegla +STR_1406 :{SMALLFONT}{BLACK}Dölj/visa dekorationer (om de finns på designen) +STR_1407 :{WINDOW_COLOUR_2}Bygg detta... +STR_1408 :{WINDOW_COLOUR_2}Kostnad: {BLACK}{CURRENCY} +STR_1409 :Ingång/utgång-Platform +STR_1410 :Vertikalt Torn +STR_1411 :{STRINGID} är i vägen +STR_1412 :{WINDOW_COLOUR_3}Den här sortens åktur kan inte spara data +STR_1413 :{WINDOW_COLOUR_3}Sparning av data börjar när nästa {STRINGID} lämnar {STRINGID} +STR_1414 :{SMALLFONT}{BLACK}{DURATION} +STR_1415 :{WINDOW_COLOUR_2}Hastighet +STR_1416 :{WINDOW_COLOUR_2}Höjd +STR_1417 :{WINDOW_COLOUR_2}Vert.G's +STR_1418 :{WINDOW_COLOUR_2}Lat.G's +STR_1419 :{SMALLFONT}{BLACK}{VELOCITY} +STR_1420 :{SMALLFONT}{BLACK}{LENGTH} +STR_1421 :{SMALLFONT}{BLACK}{COMMA16}g +STR_1422 :{SMALLFONT}{BLACK}Sparar data från {POP16}{STRINGID} +STR_1423 :{SMALLFONT}{BLACK}Kö +STR_1424 :{SMALLFONT}{BLACK}Gångväg +STR_1425 :Gångväg +STR_1426 :Kö +STR_1427 :{WINDOW_COLOUR_2}Kunder: {BLACK}{COMMA32} per timme +STR_1428 :{WINDOW_COLOUR_2}Biljettpris: +STR_1429 :{POP16}{POP16}{POP16}{CURRENCY2DP} +STR_1430 :Gratis +STR_1431 :Vandrar +STR_1432 :På väg mot {STRINGID} +STR_1433 :Köar till {STRINGID} +STR_1434 :Drunknar +STR_1435 :På {STRINGID} +STR_1436 :I {STRINGID} +STR_1437 :Vid {STRINGID} +STR_1438 :Sitter +STR_1439 :(välj plats) +STR_1440 :Klipper gräset +STR_1441 :Sopar gångvägen +STR_1442 :Tömmer sopkorgen +STR_1443 :Vattnar trädgården +STR_1444 :Kollar på {STRINGID} +STR_1445 :Kollar på konstruktionen av {STRINGID} +STR_1446 :Kollar på dekorationer +STR_1447 :Lämnar parken +STR_1448 :Kollar på konstruktionen av en ny åktur +STR_1449 :{SPRITE} {STRINGID}{NEWLINE}({STRINGID}) +STR_1450 :{INLINE_SPRITE}{09}{20}{00}{00}{SPRITE} {STRINGID}{NEWLINE}({STRINGID}) +STR_1451 :{STRINGID}{NEWLINE}({STRINGID}) +STR_1452 :Gästens namn +STR_1453 :Skriv in namn för den här gästen:- +STR_1454 :Kan inte namnge gäst... +STR_1455 :Ogiltigt gästnamn +STR_1456 :{WINDOW_COLOUR_2}Spenderade pengar: {BLACK}{CURRENCY2DP} +STR_1457 :{WINDOW_COLOUR_2}Pengar i fickan: {BLACK}{CURRENCY2DP} +STR_1458 :{WINDOW_COLOUR_2}Tid i parken: {BLACK}{REALTIME} +STR_1459 :Banstil +STR_1460 :{SMALLFONT}{BLACK}'U'-formad öppen bana +STR_1461 :{SMALLFONT}{BLACK}'O'-formad stängd bana +STR_1462 :För brant för uppskjutskulle +STR_1463 :Gäster +STR_1464 :Helix uppåt (liten) +STR_1465 :Helix uppåt (stor) +STR_1466 :Helix nedåt (liten) +STR_1467 :Helix nedåt (stor) +STR_1468 :Personal +STR_1469 :Åkturen måste påbörjas och avslutas med stationer +STR_1470 :Stationen är inte lång nog +STR_1471 :{WINDOW_COLOUR_2}Hastighet: +STR_1472 :{SMALLFONT}{BLACK}Den här åkturens hastighet +STR_1473 :{WINDOW_COLOUR_2}Glädjenivå: {BLACK}{COMMA2DP32} ({STRINGID}) +STR_1474 :{WINDOW_COLOUR_2}Glädjenivå: {BLACK}Inte tillgänglig +STR_1475 :{WINDOW_COLOUR_2}Intensitetsnivå: {BLACK}{COMMA2DP32} ({STRINGID}) +STR_1476 :{WINDOW_COLOUR_2}Intensitetsnivå: {BLACK}Inte tillgänglig +STR_1477 :{WINDOW_COLOUR_2}Intensitetsnivå: {OUTLINE}{RED}{COMMA2DP32} ({STRINGID}) +STR_1478 :{WINDOW_COLOUR_2}Illamåendenivå: {BLACK}{COMMA2DP32} ({STRINGID}) +STR_1479 :{WINDOW_COLOUR_2}Illamåendenivå: {BLACK}Inte tillgänglig +STR_1480 :{SMALLFONT}{OPENQUOTES}Jag har inte råd med {STRINGID}{ENDQUOTES} +STR_1481 :{SMALLFONT}{OPENQUOTES}Jag har spenderat alla mina pengar{ENDQUOTES} +STR_1482 :{SMALLFONT}{OPENQUOTES}Jag mår illa{ENDQUOTES} +STR_1483 :{SMALLFONT}{OPENQUOTES}Jag mår riktigt illa{ENDQUOTES} +STR_1484 :{SMALLFONT}{OPENQUOTES}Jag vill åka något mer spännande än {STRINGID}{ENDQUOTES} +STR_1485 :{SMALLFONT}{OPENQUOTES}{STRINGID} ser för intensiv ut för mig{ENDQUOTES} +STR_1486 :{SMALLFONT}{OPENQUOTES}Jag är inte klar med min {STRINGID} än{ENDQUOTES} +STR_1487 :{SMALLFONT}{OPENQUOTES}Bara att kolla på {STRINGID} får mig att må illa{ENDQUOTES} +STR_1488 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för {STRINGID}{ENDQUOTES} +STR_1489 :{SMALLFONT}{OPENQUOTES}Jag vill gå hem{ENDQUOTES} +STR_1490 :{SMALLFONT}{OPENQUOTES}{STRINGID} är verkligen värd{ENDQUOTES} +STR_1491 :{SMALLFONT}{OPENQUOTES}Jag har redan {STRINGID}{ENDQUOTES} +STR_1492 :{SMALLFONT}{OPENQUOTES}Jag har inte råd med {STRINGID}{ENDQUOTES} +STR_1493 :{SMALLFONT}{OPENQUOTES}Jag är inte hungrig{ENDQUOTES} +STR_1494 :{SMALLFONT}{OPENQUOTES}Jag är inte törstig{ENDQUOTES} +STR_1495 :{SMALLFONT}{OPENQUOTES}Hjälp! Jag drunknar!{ENDQUOTES} +STR_1496 :{SMALLFONT}{OPENQUOTES}Jag har tappat bort mig!{ENDQUOTES} +STR_1497 :{SMALLFONT}{OPENQUOTES}{STRINGID} var superkul{ENDQUOTES} +STR_1498 :{SMALLFONT}{OPENQUOTES}Jag har köat till {STRINGID} i åratal{ENDQUOTES} +STR_1499 :{SMALLFONT}{OPENQUOTES}Jag är trött{ENDQUOTES} +STR_1500 :{SMALLFONT}{OPENQUOTES}Jag är hungrig{ENDQUOTES} +STR_1501 :{SMALLFONT}{OPENQUOTES}Jag är törstig{ENDQUOTES} +STR_1502 :{SMALLFONT}{OPENQUOTES}Jag måste gå på toa{ENDQUOTES} +STR_1503 :{SMALLFONT}{OPENQUOTES}Jag kan inte hitta {STRINGID}{ENDQUOTES} +STR_1504 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för att använda {STRINGID}{ENDQUOTES} +STR_1505 :{SMALLFONT}{OPENQUOTES}Jag tänker inte åka {STRINGID} när det regnar{ENDQUOTES} +STR_1506 :{SMALLFONT}{OPENQUOTES}Nedskräpningen här är hemsk{ENDQUOTES} +STR_1507 :{SMALLFONT}{OPENQUOTES}Jag kan inte hitta parkutgången{ENDQUOTES} +STR_1508 :{SMALLFONT}{OPENQUOTES}Jag vill hoppa av {STRINGID}{ENDQUOTES} +STR_1509 :{SMALLFONT}{OPENQUOTES}Jag vill ut ur {STRINGID}{ENDQUOTES} +STR_1510 :{SMALLFONT}{OPENQUOTES}Jag tänker inte åka {STRINGID} - Det är inte säkert nog{ENDQUOTES} +STR_1511 :{SMALLFONT}{OPENQUOTES}Den här gångvägen är vidrig{ENDQUOTES} +STR_1512 :{SMALLFONT}{OPENQUOTES}Det är för mycket folk här{ENDQUOTES} +STR_1513 :{SMALLFONT}{OPENQUOTES}The vandalism here is really bad{ENDQUOTES} +STR_1514 :{SMALLFONT}{OPENQUOTES}Snygga dekorationer!{ENDQUOTES} +STR_1515 :{SMALLFONT}{OPENQUOTES}Den här parken är verkligen ren och fin{ENDQUOTES} +STR_1516 :{SMALLFONT}{OPENQUOTES}Fontänerna är fantastiska{ENDQUOTES} +STR_1517 :{SMALLFONT}{OPENQUOTES}Musiken här är trevlig{ENDQUOTES} +STR_1518 :{SMALLFONT}{OPENQUOTES}Ballongen från {STRINGID} var verkligen värd pengarna{ENDQUOTES} +STR_1519 :{SMALLFONT}{OPENQUOTES}Kramdjuret från {STRINGID} var verkligen värt pengarna{ENDQUOTES} +STR_1520 :{SMALLFONT}{OPENQUOTES}Kartan från {STRINGID} var verkligen värd pengarna{ENDQUOTES} +STR_1521 :{SMALLFONT}{OPENQUOTES}Fotot från åkturen {STRINGID} var verkligen värt pengarna{ENDQUOTES} +STR_1522 :{SMALLFONT}{OPENQUOTES}Paraplyt från {STRINGID} var verkligen värt pengarna{ENDQUOTES} +STR_1523 :{SMALLFONT}{OPENQUOTES}Drickan från {STRINGID} var verkligen värd pengarna{ENDQUOTES} +STR_1524 :{SMALLFONT}{OPENQUOTES}Hamburgaren från {STRINGID} var verkligen värd pengarna{ENDQUOTES} +STR_1525 :{SMALLFONT}{OPENQUOTES}Pommes fritesen från {STRINGID} var verkligen värda pengarna{ENDQUOTES} +STR_1526 :{SMALLFONT}{OPENQUOTES}Glassen från {STRINGID} var verkligen värd pengarna{ENDQUOTES} +STR_1527 :{SMALLFONT}{OPENQUOTES}Sockervadden från {STRINGID} var verkligen värd pengarna{ENDQUOTES} +STR_1528 : +STR_1529 : +STR_1530 : +STR_1531 :{SMALLFONT}{OPENQUOTES}Pizzan från {STRINGID} var verkligen värd pengarna{ENDQUOTES} +STR_1532 : +STR_1533 :{SMALLFONT}{OPENQUOTES}Popcornen från {STRINGID} var verkligen värda pengarna{ENDQUOTES} +STR_1534 :{SMALLFONT}{OPENQUOTES}Varmkorven från {STRINGID} var verkligen värd pengarna{ENDQUOTES} +STR_1535 :{SMALLFONT}{OPENQUOTES}Tentakeln från {STRINGID} var verkligen värd pengarna{ENDQUOTES} +STR_1536 :{SMALLFONT}{OPENQUOTES}Hatten från {STRINGID} var verkligen värd pengarna{ENDQUOTES} +STR_1537 :{SMALLFONT}{OPENQUOTES}Kanderat äpplet från {STRINGID} var verkligen värt pengarna{ENDQUOTES} +STR_1538 :{SMALLFONT}{OPENQUOTES}T-shirten från {STRINGID} var verkligen värd pengarna{ENDQUOTES} +STR_1539 :{SMALLFONT}{OPENQUOTES}Donuten från {STRINGID} var verkligen värd pengarna{ENDQUOTES} +STR_1540 :{SMALLFONT}{OPENQUOTES}Kaffet från {STRINGID} var verkligen värt pengarna{ENDQUOTES} +STR_1541 : +STR_1542 :{SMALLFONT}{OPENQUOTES}Friterade kycklingen från {STRINGID} var verkligen värd pengarna{ENDQUOTES} +STR_1543 :{SMALLFONT}{OPENQUOTES}Saften från {STRINGID} var verkligen värd pengarna{ENDQUOTES} +STR_1544 : +STR_1545 : +STR_1546 : +STR_1547 : +STR_1548 : +STR_1549 : +STR_1550 :{SMALLFONT}{OPENQUOTES}Wow!{ENDQUOTES} +STR_1551 :{SMALLFONT}{OPENQUOTES}Det känns som att någon iakttar mig{ENDQUOTES} +STR_1552 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för Jag tänker inte betala så mycket för a balloon from {STRINGID}{ENDQUOTES} +STR_1553 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för ett mjukisdjur från {STRINGID}{ENDQUOTES} +STR_1554 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för en karta från {STRINGID}{ENDQUOTES} +STR_1555 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för ett foto från åkturen {STRINGID}{ENDQUOTES} +STR_1556 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för ett paraply från {STRINGID}{ENDQUOTES} +STR_1557 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för en dricka från {STRINGID}{ENDQUOTES} +STR_1558 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för en hamburgare från {STRINGID}{ENDQUOTES} +STR_1559 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för pommes frites från {STRINGID}{ENDQUOTES} +STR_1560 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för en glass från {STRINGID}{ENDQUOTES} +STR_1561 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för sockervadd från {STRINGID}{ENDQUOTES} +STR_1562 : +STR_1563 : +STR_1564 : +STR_1565 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för pizza from {STRINGID}{ENDQUOTES} +STR_1566 : +STR_1567 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för popcorn från {STRINGID}{ENDQUOTES} +STR_1568 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för en varmkorv från {STRINGID}{ENDQUOTES} +STR_1569 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för tentakel från {STRINGID}{ENDQUOTES} +STR_1570 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för en hatt från {STRINGID}{ENDQUOTES} +STR_1571 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för ett kanderat äpple från {STRINGID}{ENDQUOTES} +STR_1572 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för en T-shirt från {STRINGID}{ENDQUOTES} +STR_1573 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för en donut från {STRINGID}{ENDQUOTES} +STR_1574 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för en kaffe från {STRINGID}{ENDQUOTES} +STR_1575 : +STR_1576 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för friterad kyckling från {STRINGID}{ENDQUOTES} +STR_1577 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för saft från {STRINGID}{ENDQUOTES} +STR_1578 : +STR_1579 : +STR_1580 : +STR_1581 : +STR_1582 : +STR_1583 : +STR_1584 :{SMALLFONT}{OPENQUOTES}Fotot från åkturen {STRINGID} var verkligen värt pengarna{ENDQUOTES} +STR_1585 :{SMALLFONT}{OPENQUOTES}Fotot från åkturen {STRINGID} var verkligen värt pengarna{ENDQUOTES} +STR_1586 :{SMALLFONT}{OPENQUOTES}Fotot från åkturen {STRINGID} var verkligen värt pengarna{ENDQUOTES} +STR_1587 :{SMALLFONT}{OPENQUOTES}Pretzeln från {STRINGID} var verkligen värd pengarna{ENDQUOTES} +STR_1588 :{SMALLFONT}{OPENQUOTES}Varma chokladen från {STRINGID} var verkligen värd pengarna{ENDQUOTES} +STR_1589 :{SMALLFONT}{OPENQUOTES}Istéet från {STRINGID} var verkligen värt pengarna{ENDQUOTES} +STR_1590 :{SMALLFONT}{OPENQUOTES}Struvan från {STRINGID} var verkligen värd pengarna{ENDQUOTES} +STR_1591 :{SMALLFONT}{OPENQUOTES}Solglasögonen från {STRINGID} var verkligen värda pengarna{ENDQUOTES} +STR_1592 :{SMALLFONT}{OPENQUOTES}Biffnudlarna från {STRINGID} var verkligen värda pengarna{ENDQUOTES} +STR_1593 :{SMALLFONT}{OPENQUOTES}De stekta nudlarna från {STRINGID} var verkligen värda pengarna{ENDQUOTES} +STR_1594 :{SMALLFONT}{OPENQUOTES}Wontonsoppan från {STRINGID} var verkligen värd pengarna{ENDQUOTES} +STR_1595 :{SMALLFONT}{OPENQUOTES}Köttbullssoppan från {STRINGID} var verkligen värd pengarna{ENDQUOTES} +STR_1596 :{SMALLFONT}{OPENQUOTES}Fruktjuicen från {STRINGID} var verkligen värd pengarna{ENDQUOTES} +STR_1597 :{SMALLFONT}{OPENQUOTES}Sojamjölken från {STRINGID} var verkligen värd pengarna{ENDQUOTES} +STR_1598 :{SMALLFONT}{OPENQUOTES}Sujeonggwan från {STRINGID} var verkligen värd pengarna{ENDQUOTES} +STR_1599 :{SMALLFONT}{OPENQUOTES}Mackan från {STRINGID} var verkligen värd pengarna{ENDQUOTES} +STR_1600 :{SMALLFONT}{OPENQUOTES}Kakan från {STRINGID} var verkligen värd pengarna{ENDQUOTES} +STR_1601 : +STR_1602 : +STR_1603 : +STR_1604 :{SMALLFONT}{OPENQUOTES}Ugnskorven från {STRINGID} var verkligen värd pengarna{ENDQUOTES} +STR_1605 : +STR_1606 : +STR_1607 : +STR_1608 : +STR_1609 : +STR_1610 : +STR_1611 : +STR_1612 : +STR_1613 : +STR_1614 : +STR_1615 : +STR_1616 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för ett foto från åkturen {STRINGID}{ENDQUOTES} +STR_1617 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för ett foto från åkturen {STRINGID}{ENDQUOTES} +STR_1618 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för ett foto från åkturen {STRINGID}{ENDQUOTES} +STR_1619 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för en pretzel från {STRINGID}{ENDQUOTES} +STR_1620 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för varm choklad från {STRINGID}{ENDQUOTES} +STR_1621 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för isté från {STRINGID}{ENDQUOTES} +STR_1622 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för en struva från {STRINGID}{ENDQUOTES} +STR_1623 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för solglasögon från {STRINGID}{ENDQUOTES} +STR_1624 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för biffnudlar från {STRINGID}{ENDQUOTES} +STR_1625 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för stekta nudlar från {STRINGID}{ENDQUOTES} +STR_1626 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för wontonsoppa från {STRINGID}{ENDQUOTES} +STR_1627 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för köttbullssoppa från {STRINGID}{ENDQUOTES} +STR_1628 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för fruktjuice från {STRINGID}{ENDQUOTES} +STR_1629 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för sojamjölk från {STRINGID}{ENDQUOTES} +STR_1630 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för sujeonggwa från {STRINGID}{ENDQUOTES} +STR_1631 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för en macka från {STRINGID}{ENDQUOTES} +STR_1632 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för en kaka från {STRINGID}{ENDQUOTES} +STR_1633 : +STR_1634 : +STR_1635 : +STR_1636 :{SMALLFONT}{OPENQUOTES}Jag tänker inte betala så mycket för en ugnskorv från {STRINGID}{ENDQUOTES} +STR_1637 : +STR_1638 : +STR_1639 : +STR_1640 : +STR_1641 : +STR_1642 : +STR_1643 : +STR_1644 : +STR_1645 : +STR_1646 : +STR_1647 : +STR_1648 :{SMALLFONT}{OPENQUOTES}Hjälp! Släpp ner mig!{ENDQUOTES} +STR_1649 :{SMALLFONT}{OPENQUOTES}Jag börjar få slut på pengar!{ENDQUOTES} +STR_1650 :{SMALLFONT}{OPENQUOTES}Wow! Dom bygger en ny åktur!{ENDQUOTES} +STR_1651 :{SMALLFONT}{OPENQUOTES}Najs åktur! Men inte lika bra som Fenixen...{ENDQUOTES} +STR_1652 :{SMALLFONT}{OPENQUOTES}Jag är så taggad - Det är en Intamin-åktur!{ENDQUOTES} +STR_1653 :{SMALLFONT}{OPENQUOTES}...och nu är vi på {STRINGID}!{ENDQUOTES} +STR_1654 :{WINDOW_COLOUR_2}Nyliga tankar: +STR_1655 :{SMALLFONT}{BLACK}Bygg gångväg på land +STR_1656 :{SMALLFONT}{BLACK}Bygg en bro eller tunnel +STR_1657 :{WINDOW_COLOUR_2}Favoritåktur +STR_1658 :{WINDOW_COLOUR_2}intensitet: {BLACK}mindre än {COMMA16} +STR_1659 :{WINDOW_COLOUR_2}intensitet: {BLACK}mellan {COMMA16} och {COMMA16} +STR_1660 :{WINDOW_COLOUR_2}intensitet: {BLACK}mer än {COMMA16} +STR_1661 :{WINDOW_COLOUR_2}Tolerans för illamående: {BLACK}{STRINGID} +STR_1662 :{WINDOW_COLOUR_2}Glädje: +STR_1663 :{WINDOW_COLOUR_2}Illamående: +STR_1664 :{WINDOW_COLOUR_2}Energi: +STR_1665 :{WINDOW_COLOUR_2}Hunger: +STR_1666 :{WINDOW_COLOUR_2}Törst: +STR_1667 :{WINDOW_COLOUR_2}Blåsa: +STR_1668 :{WINDOW_COLOUR_2}Tillfredställdhet: {BLACK}Okänd +STR_1669 :{WINDOW_COLOUR_2}Tillfredställdhet: {BLACK}{COMMA16}% +STR_1670 :{WINDOW_COLOUR_2}Totalt antal kunder: {BLACK}{COMMA32} +STR_1671 :{WINDOW_COLOUR_2}Total vinst: {BLACK}{CURRENCY2DP} +STR_1672 :Bromsar +#TODO +STR_1673 :Spinning Control Toggle Track +STR_1674 :Bromshastighet +STR_1675 :{POP16}{VELOCITY} +STR_1676 :{SMALLFONT}{BLACK}Sätt hastighetsgräns för bromsar +STR_1677 :{WINDOW_COLOUR_2}Popularitet: {BLACK}Okänd +STR_1678 :{WINDOW_COLOUR_2}Popularitet: {BLACK}{COMMA16}% +STR_1679 :Helix uppåt (vänster) +STR_1680 :Helix uppåt (höger) +STR_1681 :Helix nedåt (vänster) +STR_1682 :Helix nedåt (höger) +STR_1683 :Basstorlek 2 x 2 +STR_1684 :Basstorlek 4 x 4 +STR_1685 :Basstorlek 2 x 4 +STR_1686 :Basstorlek 5 x 1 +STR_1687 :Vattenplums +STR_1688 :Basstorlek 4 x 1 +STR_1689 :Blockbromsar +STR_1690 :{WINDOW_COLOUR_2}{STRINGID}{NEWLINE}{BLACK}{STRINGID} +STR_1691 :{WINDOW_COLOUR_2} Kostnad: {BLACK}{CURRENCY} +STR_1692 :{WINDOW_COLOUR_2} Kostnad: {BLACK}från {CURRENCY} +STR_1693 :{SMALLFONT}{BLACK}Gäster +STR_1694 :{SMALLFONT}{BLACK}Personal +STR_1695 :{SMALLFONT}{BLACK}Inkomst och utgifter +STR_1696 :{SMALLFONT}{BLACK}Kundinformation +STR_1697 :Kan inte placera dessa i ett köområde +STR_1698 :Kan endast placera dessa i ett köområde +STR_1699 :För mycket folk i spelet +STR_1700 :Anställ ny Vaktmästare +STR_1701 :Anställ ny Mekaniker +STR_1702 :Anställ ny Säkerhetsvakt +STR_1703 :Anställ ny Underhållare +STR_1704 :Kan inte anställa ny personal... +STR_1705 :{SMALLFONT}{BLACK}Sparka den här personalen +STR_1706 :{SMALLFONT}{BLACK}Flytta den här personen till en ny plats +STR_1707 :För mycket personal i spelet +STR_1708 :{SMALLFONT}{BLACK}Bestäm patrullområde för den här personalen +STR_1709 :Sparka personal +STR_1710 :Ja +STR_1711 :{WINDOW_COLOUR_1}Är du säker på att du vill sparka {STRINGID}? +STR_1712 :{INLINE_SPRITE}{247}{19}{00}{00}{WINDOW_COLOUR_2}Sopa gångvägar +STR_1713 :{INLINE_SPRITE}{248}{19}{00}{00}{WINDOW_COLOUR_2}Vattna trädgårdar +STR_1714 :{INLINE_SPRITE}{249}{19}{00}{00}{WINDOW_COLOUR_2}Töm sopkorgar +STR_1715 :{INLINE_SPRITE}{250}{19}{00}{00}{WINDOW_COLOUR_2}Klipp gräs +STR_1716 :Ogiltigt parknamn +STR_1717 :Kan inte namnge park... +STR_1718 :Parknamn +STR_1719 :Skriv in namn på parken:- +STR_1720 :{SMALLFONT}{BLACK}Namnge park +STR_1721 :Parken är stängd +STR_1722 :Parken är öppen +STR_1723 :Kan inte öppna parken... +STR_1724 :Kan inte stänga parken... +STR_1725 :Kan inte köpa mark... +STR_1726 :Marken är inte till salu! +STR_1727 :Bygglov är inte till salu! +STR_1728 :Kan inte få bygglov här... +STR_1729 :Marken ägs inte av parken! +STR_1730 :{RED}Stängd - - +STR_1731 :{WHITE}{STRINGID} - - +STR_1732 :Bygg +STR_1733 :Läge +STR_1734 :{WINDOW_COLOUR_2}Antal varv: +STR_1735 :{SMALLFONT}{BLACK}Antal varv +STR_1736 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1737 :{COMMA16} +STR_1738 :Kan inte ändra antal varv... +STR_1739 :Gäst {INT32} vann rallyt +STR_1740 :{STRINGID} vann rallyt +STR_1741 :Inte byggt än ! +STR_1742 :{WINDOW_COLOUR_2}Max. people on Åktur: +STR_1743 :{SMALLFONT}{BLACK}Maximum number of people allowed on this Åktur at one time +STR_1744 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1745 :{COMMA16} +STR_1746 :Can't change this... +STR_1747 :{WINDOW_COLOUR_2}Tidsgräns: +STR_1748 :{SMALLFONT}{BLACK}Tidsgräns för åkturen +STR_1749 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{DURATION} +STR_1750 :{DURATION} +STR_1751 :Kan inte ändra tidsgränsen för åkturen... +STR_1752 :{SMALLFONT}{BLACK}Visa lista över individuella gäster i parken +STR_1753 :{SMALLFONT}{BLACK}Visa sammanfattning av alla gäster i parken +STR_1754 :{BLACK}{COMMA16} gäster +STR_1755 :{BLACK}{COMMA16} gäst +STR_1756 :{WINDOW_COLOUR_2}Biljettpris: +STR_1757 :{WINDOW_COLOUR_2}Tillförlitlighet: {MOVE_X}{255}{BLACK}{COMMA16}% +STR_1758 :{SMALLFONT}{BLACK}Byggläge +STR_1759 :{SMALLFONT}{BLACK}Flyttläge +STR_1760 :{SMALLFONT}{BLACK}Fyll-i-läge +STR_1761 :{SMALLFONT}{BLACK}Bygg labyrint i denna riktning +STR_1762 :Vattenfall +STR_1763 :Strider +STR_1764 :Stockar +STR_1765 :Fotosektion +STR_1766 :Omvändare +STR_1767 :Snurrande tunnel +STR_1768 :Kan inte ändra antalet gungningar... +STR_1769 :{WINDOW_COLOUR_2}Antal gungningar: +STR_1770 :{SMALLFONT}{BLACK}Antal hela gungningar +STR_1771 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1772 :{COMMA16} +STR_1773 :Bara en fotosektion tillåten per åktur +STR_1774 :Bara en uppskjutskulle tillåten per åktur +STR_1775 :Av +STR_1776 :På +STR_1777 :{WINDOW_COLOUR_2}Musik: +STR_1778 :{STRINGID} - - +STR_1779 :{INLINE_SPRITE}{254}{19}{00}{00} Pandadräkt +STR_1780 :{INLINE_SPRITE}{255}{19}{00}{00} Tigerdräkt +STR_1781 :{INLINE_SPRITE}{00}{20}{00}{00} Elefantdräkt +STR_1782 :{INLINE_SPRITE}{01}{20}{00}{00} Romersk dräkt +STR_1783 :{INLINE_SPRITE}{02}{20}{00}{00} Gorilladräkt +STR_1784 :{INLINE_SPRITE}{03}{20}{00}{00} Snögubbedräkt +STR_1785 :{INLINE_SPRITE}{04}{20}{00}{00} Riddardräkt +STR_1786 :{INLINE_SPRITE}{05}{20}{00}{00} Astronautdräkt +STR_1787 :{INLINE_SPRITE}{06}{20}{00}{00} Banditdräkt +STR_1788 :{INLINE_SPRITE}{07}{20}{00}{00} Sheriffdräkt +STR_1789 :{INLINE_SPRITE}{08}{20}{00}{00} Piratdräkt +STR_1790 :{SMALLFONT}{BLACK}Välj uniformfärg för den här sortens personal +STR_1791 :{WINDOW_COLOUR_2}Uniformfärg: +STR_1792 :Svarar på radioanrop om {STRINGID} +STR_1793 :På väg till {STRINGID} för en inspektion +STR_1794 :Fixar {STRINGID} +STR_1795 :Svarar på radioanrop +STR_1796 :Har gått sönder och behöver fixas +STR_1797 :Denna inställning kan inte ändras på den här åkturen +STR_1798 :Strömvirvel +STR_1799 :{POP16}{POP16}{POP16}{POP16}{POP16}{CURRENCY2DP} +STR_1800 :Nödstopp +STR_1801 :Byglarna kan ej fällas ner +STR_1802 :Byglarna kan ej fällas upp +STR_1803 :Dörrarna går inte att öppna +STR_1804 :Dörrarna går inte att stänga +STR_1805 :Fordonshaveri +STR_1806 :Bromsfel +STR_1807 :Kontrollfel +STR_1808 :{WINDOW_COLOUR_2}Senaste haveri: {BLACK}{STRINGID} +STR_1809 :{WINDOW_COLOUR_2}Nuvarande haveri: {OUTLINE}{RED}{STRINGID} +STR_1810 :{WINDOW_COLOUR_2}Bär på: +STR_1811 :Kan inte bygga detta här... +STR_1812 :{SMALLFONT}{BLACK}{STRINGID} +STR_1813 :Diverse Saker +STR_1814 :Handlingar +STR_1815 :Tankar +STR_1816 :{SMALLFONT}{BLACK}Välj informationstyp som ska visas i gästlistan +STR_1817 :({COMMA16}) +STR_1818 :{WINDOW_COLOUR_2}Alla gäster +STR_1819 :{WINDOW_COLOUR_2}Alla gäster (sammanfattat) +STR_1820 :{WINDOW_COLOUR_2}Gäster {STRINGID} +STR_1821 :{WINDOW_COLOUR_2}Gäster som tänker {STRINGID} +STR_1822 :{WINDOW_COLOUR_2}Guests som tänker på {POP16}{STRINGID} +STR_1823 :{SMALLFONT}{BLACK}Visa gästers tankar om den här åkturen/attraktionen +STR_1824 :{SMALLFONT}{BLACK}Visa gäster på den här åkturen/attraktionen +STR_1825 :{SMALLFONT}{BLACK}Visa gäster som köar till den här åkturen/attraktionen +STR_1826 :Status +STR_1827 :Popularitet +STR_1828 :Tillfredsställdhet +STR_1829 :Vinst +STR_1830 :Kölängd +STR_1831 :Kötid +STR_1832 :Tillförlitlighet +STR_1833 :Dötid +STR_1834 :Gästernas favorit +STR_1835 :Popularitet: Okänd +STR_1836 :Popularitet: {COMMA16}% +STR_1837 :Tillfredsställdhet: Okänd +STR_1838 :Tillfredsställdhet: {COMMA16}% +STR_1839 :Tillförlitlighet: {COMMA16}% +STR_1840 :Dötid: {COMMA16}% +STR_1841 :Vinst: {CURRENCY} per timme +STR_1842 :{COMMA16} gästs favorit +STR_1843 :{COMMA16} gästers favorit +STR_1844 :{SMALLFONT}{BLACK}Välj informationstyp som ska visas i åkturs/attraktions-listan +STR_1845 :{MONTHYEAR} +STR_1846 :{COMMA16} gäster +STR_1847 :{INLINE_SPRITE}{11}{20}{00}{00}{COMMA16} gäster +STR_1848 :{INLINE_SPRITE}{10}{20}{00}{00}{COMMA16} gäster +STR_1849 :{WINDOW_COLOUR_2}Spela musik +STR_1850 :{SMALLFONT}{BLACK}Välj om musik ska spelas på denna åktur +STR_1851 :{WINDOW_COLOUR_2}Underhållskostnad: {BLACK}{CURRENCY2DP} per timme +STR_1852 :{WINDOW_COLOUR_2}Underhållskostnad: {BLACK}Okänd +STR_1853 :{WINDOW_COLOUR_2}Byggd: {BLACK}Detta år +STR_1854 :{WINDOW_COLOUR_2}Byggd: {BLACK}Förra året +STR_1855 :{WINDOW_COLOUR_2}Byggd: {BLACK}{COMMA16} År sen +STR_1856 :{WINDOW_COLOUR_2}Vinst per styck: {BLACK}{CURRENCY2DP} +STR_1857 :{WINDOW_COLOUR_2}Förlust per styck: {BLACK}{CURRENCY2DP} +STR_1858 :{WINDOW_COLOUR_2}Kostnad: {BLACK}{CURRENCY} per månad +STR_1859 :Vaktmästare +STR_1860 :Mekaniker +STR_1861 :Säkerhetsvakter +STR_1862 :Underhållare +STR_1863 :Vaktmästare +STR_1864 :Mekaniker +STR_1865 :Säkerhetsvakt +STR_1866 :Underhållare +STR_1867 :{BLACK}{COMMA16} {STRINGID} +STR_1868 :Kan inte ändra antal rotationer... +STR_1869 :{WINDOW_COLOUR_2}Antal rotationer: +STR_1870 :{SMALLFONT}{BLACK}Antal hela rotationer +STR_1871 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1872 :{COMMA16} +STR_1873 :{WINDOW_COLOUR_2}Inkomst: {BLACK}{CURRENCY} per timme +STR_1874 :{WINDOW_COLOUR_2}Vinst: {BLACK}{CURRENCY} per timme +STR_1875 :{BLACK} {SPRITE}{BLACK} {STRINGID} +STR_1876 :{WINDOW_COLOUR_2}{INLINE_SPRITE}{251}{19}{00}{00}Inspektera åkturer +STR_1877 :{WINDOW_COLOUR_2}{INLINE_SPRITE}{252}{19}{00}{00}Fixa åkturer +STR_1878 :{WINDOW_COLOUR_2}Inspektion: +STR_1879 :Var 10:e minut +STR_1880 :Var 20:e minut +STR_1881 :Var 30:e minut +STR_1882 :Var 45:e minut +STR_1883 :Varje timme +STR_1884 :Varannan timme +STR_1885 :Aldrig +STR_1886 :Inspekterar {STRINGID} +STR_1887 :{WINDOW_COLOUR_2}Tid sen senaste inspektion: {BLACK}{COMMA16} minuter +STR_1888 :{WINDOW_COLOUR_2}Tid sen senaste inspektion: {BLACK}mer än 4 timmar +STR_1889 :{WINDOW_COLOUR_2}Dötid: {MOVE_X}{255}{BLACK}{COMMA16}% +STR_1890 :{SMALLFONT}{BLACK}Välj hur ofta en mekaniker ska göra underhåll på den här åkturen +STR_1891 :Ingen {STRINGID} i parken än! +STR_1892 :RollerCoaster Tycoon 2 +STR_1893 :Var god sätt in din RollerCoaster Tycoon 2-skiva i följande CD-läsare:- +STR_1894 :{WINDOW_COLOUR_2}{STRINGID} sålde: {BLACK}{COMMA32} +STR_1895 :{SMALLFONT}{BLACK}Bygg ny Åktur/attraktion +STR_1896 :{WINDOW_COLOUR_2}Utgifter/Inkomster +STR_1897 :{WINDOW_COLOUR_2}Åkturskonstruktioner +STR_1898 :{WINDOW_COLOUR_2}Åktursunderhållskonstnader +STR_1899 :{WINDOW_COLOUR_2}Markinköp +STR_1900 :{WINDOW_COLOUR_2}Terrängmodifiering +STR_1901 :{WINDOW_COLOUR_2}Parkinträde +STR_1902 :{WINDOW_COLOUR_2}Åktursbiljetter +STR_1903 :{WINDOW_COLOUR_2}Sålda varor +STR_1904 :{WINDOW_COLOUR_2}Affärslager +STR_1905 :{WINDOW_COLOUR_2}Såld mat/dryck +STR_1906 :{WINDOW_COLOUR_2}Mat/dryck-lager +STR_1907 :{WINDOW_COLOUR_2}Löner +STR_1908 :{WINDOW_COLOUR_2}Marknadsföring +STR_1909 :{WINDOW_COLOUR_2}Forskning +STR_1910 :{WINDOW_COLOUR_2}Låneränta +STR_1911 :{BLACK} på {COMMA16}% per år +STR_1912 :{MONTH} +STR_1913 :{BLACK}+{CURRENCY2DP} +STR_1914 :{BLACK}{CURRENCY2DP} +STR_1915 :{RED}{CURRENCY2DP} +STR_1916 :{WINDOW_COLOUR_2}Lån: +STR_1917 :{POP16}{POP16}{POP16}{CURRENCY} +STR_1918 :Kan inte låna mer pengar! +STR_1919 :Inte nog med pengar tillgängliga! +STR_1920 :Kan inte betala tillbaka lån! +STR_1921 :{SMALLFONT}{BLACK}Starta ett nytt spel +STR_1922 :{SMALLFONT}{BLACK}Fortsätt spela ett sparat spel +STR_1923 :{SMALLFONT}{BLACK}Visa handledning +STR_1924 :{SMALLFONT}{BLACK}Avsluta +STR_1925 :Kan inte placera personen här... +STR_1926 :{SMALLFONT} +STR_1927 :{YELLOW}{STRINGID} har gått sönder +STR_1928 :{RED}{STRINGID} har kraschat! +STR_1929 :{RED}{STRINGID} har fortfarande inte blivit fixad{NEWLINE}Kolla var dina mekaniker är och överväg att organisera dom bättre +STR_1930 :{SMALLFONT}{BLACK}Aktivera/inaktivera spårning av denna gäst - (Om spårning är på så kommer gästens handlingar att visas i meddelandeområdet) +STR_1931 :{STRINGID} har ställt sig i kö till {STRINGID} +STR_1932 :{STRINGID} är på {STRINGID} +STR_1933 :{STRINGID} är i {STRINGID} +STR_1934 :{STRINGID} har lämnat {STRINGID} +STR_1935 :{STRINGID} has lämnat parken +STR_1936 :{STRINGID} har köpt {STRINGID} +STR_1937 :{SMALLFONT}{BLACK}Visa information om meddelandets ämne +STR_1938 :{SMALLFONT}{BLACK}Visa gästvyn +STR_1939 :{SMALLFONT}{BLACK}Visa personalvyn +STR_1940 :{SMALLFONT}{BLACK}Visa glädje, energi, hunger etc. för denna gäst +STR_1941 :{SMALLFONT}{BLACK}Visa vilka åkturer denna gäst har varit på +STR_1942 :{SMALLFONT}{BLACK}Visa ekonomisk information om denna gäst +STR_1943 :{SMALLFONT}{BLACK}Visa gästens nyliga tankar +STR_1944 :{SMALLFONT}{BLACK}Visa souvenirer som gästen bär på +STR_1945 :{SMALLFONT}{BLACK}Visa order och inställningar för personal +STR_1946 :{SMALLFONT}{BLACK}Välj dräkt för den här underhållaren +STR_1947 :{SMALLFONT}{BLACK}Visa områden som patrulleras av den valda personaltypen, och hitta den närmsta personalen +STR_1948 :{SMALLFONT}{BLACK}Anställ ny personal av den valda typen +STR_1949 :Ekonomisk Sammanfattning +STR_1950 :Ekonomigraf +STR_1951 :Parkvärdesgraf +STR_1952 :Vinstgraf +STR_1953 :Marknadsföring +STR_1954 :Forskningsbidrag +STR_1955 :{WINDOW_COLOUR_2}Antal varv: +STR_1956 :{SMALLFONT}{BLACK}Antal varv per åk +STR_1957 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1958 :{COMMA16} +STR_1959 :Kan inte ändra antal varv... +STR_1960 :{WINDOW_COLOUR_2}Pris på Ballong: +STR_1961 :{WINDOW_COLOUR_2}Pris på Mjukisdjur: +STR_1962 :{WINDOW_COLOUR_2}Pris på Karta: +STR_1963 :{WINDOW_COLOUR_2}Pris på Åktursfoto: +STR_1964 :{WINDOW_COLOUR_2}Pris på Paraply: +STR_1965 :{WINDOW_COLOUR_2}Pris på Dricka: +STR_1966 :{WINDOW_COLOUR_2}Pris på Hamburgare: +STR_1967 :{WINDOW_COLOUR_2}Pris på Pommes frites: +STR_1968 :{WINDOW_COLOUR_2}Pris på Glass: +STR_1969 :{WINDOW_COLOUR_2}Pris på Sockervadd: +STR_1970 :{WINDOW_COLOUR_2} +STR_1971 :{WINDOW_COLOUR_2} +STR_1972 :{WINDOW_COLOUR_2} +STR_1973 :{WINDOW_COLOUR_2}Pris på Pizza: +STR_1974 :{WINDOW_COLOUR_2} +STR_1975 :{WINDOW_COLOUR_2}Pris på Popcorn: +STR_1976 :{WINDOW_COLOUR_2}Pris på Varmkorv: +STR_1977 :{WINDOW_COLOUR_2}Pris på Tentakel: +STR_1978 :{WINDOW_COLOUR_2}Pris på Hatt: +STR_1979 :{WINDOW_COLOUR_2}Pris på Kanderat Äpple: +STR_1980 :{WINDOW_COLOUR_2}Pris på T-Shirt: +STR_1981 :{WINDOW_COLOUR_2}Pris på Donut: +STR_1982 :{WINDOW_COLOUR_2}Pris på Kaffe: +STR_1983 :{WINDOW_COLOUR_2} +STR_1984 :{WINDOW_COLOUR_2}Pris på Friterad Kyckling: +STR_1985 :{WINDOW_COLOUR_2}Pris på Saft: +STR_1986 :{WINDOW_COLOUR_2} +STR_1987 :{WINDOW_COLOUR_2} +STR_1988 :Ballong +STR_1989 :Mjukisdjur +STR_1990 :Karta +STR_1991 :Åktursfoto +STR_1992 :Paraply +STR_1993 :Dricka +STR_1994 :Hamburgare +STR_1995 :Pommes Frites +STR_1996 :Glass +STR_1997 :Sockervadd +STR_1998 :Tom Mugg +STR_1999 :Skräp +STR_2000 :Tom Förpackning +STR_2001 :Pizza +STR_2002 :Kupong +STR_2003 :Popcorn +STR_2004 :Varmkorv +STR_2005 :Tentakel +STR_2006 :Hatt +STR_2007 :Kanderat Äpple +STR_2008 :T-Shirt +STR_2009 :Donut +STR_2010 :Kaffe +STR_2011 :Tom Mugg +STR_2012 :Friterad Kyckling +STR_2013 :Saft +STR_2014 :Tom Låda +STR_2015 :Tomflaska +STR_2016 :Ballonger +STR_2017 :Mjukisdjur +STR_2018 :Kartor +STR_2019 :Åktursfoton +STR_2020 :Paraplyn +STR_2021 :Drickor +STR_2022 :Hamburgare +STR_2023 :Pommes Frites +STR_2024 :Glassar +STR_2025 :Sockervadd +STR_2026 :Tomburkar +STR_2027 :Skräp +STR_2028 :Tomma Förpackningar +STR_2029 :Pizzor +STR_2030 :Kuponger +STR_2031 :Popcorn +STR_2032 :Varmkorvar +STR_2033 :Tentakler +STR_2034 :Hattar +STR_2035 :Kanderade Äpplen +STR_2036 :T-Shirts +STR_2037 :Donuts +STR_2038 :Kaffekoppar +STR_2039 :Tomma Muggar +STR_2040 :Friterad Kyckling +STR_2041 :Saft +STR_2042 :Tomma Lådor +STR_2043 :Tomflaskor +STR_2044 :en Ballong +STR_2045 :ett Mjukisdjur +STR_2046 :en Karta +STR_2047 :ett Åktursfoto +STR_2048 :ett Paraply +STR_2049 :en Dricka +STR_2050 :en Hamburgare +STR_2051 :Pommes Frites +STR_2052 :en Glass +STR_2053 :Sockervadd +STR_2054 :en Tomburk +STR_2055 :Skräp +STR_2056 :en Tom Förpackning +STR_2057 :en Pizza +STR_2058 :en Kupong +STR_2059 :Popcorn +STR_2060 :en Varmkorv +STR_2061 :en Tentakel +STR_2062 :en Hatt +STR_2063 :ett Kanderat Äpple +STR_2064 :en T-Shirt +STR_2065 :en Donut +STR_2066 :en Kaffe +STR_2067 :en Tom Mugg +STR_2068 :Friterad Kyckling +STR_2069 :Saft +STR_2070 :en Tom Låda +STR_2071 :en Tomflaska +STR_2072 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Ballong +STR_2073 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Mjukisdjur +STR_2074 :Karta över {STRINGID} +STR_2075 :Åktursfoto från {STRINGID} +STR_2076 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Paraply +STR_2077 :Dricka +STR_2078 :Hamburgare +STR_2079 :Pommes Frites +STR_2080 :Glass +STR_2081 :Sockervadd +STR_2082 :Tomburk +STR_2083 :Skräp +STR_2084 :Tom Förpackning +STR_2085 :Pizza +STR_2086 :Kupong för {STRINGID} +STR_2087 :Popcorn +STR_2088 :Varmkorv +STR_2089 :Tentakel +STR_2090 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Hatt +STR_2091 :Kanderat Äpple +STR_2092 :{OPENQUOTES}{STRINGID}{ENDQUOTES} T-Shirt +STR_2093 :Donut +STR_2094 :Kaffe +STR_2095 :Tom Mugg +STR_2096 :Friterad Kyckling +STR_2097 :Saft +STR_2098 :Tom Låda +STR_2099 :Tomflaska +STR_2100 :{WINDOW_COLOUR_2}Pris på Åktursfoto: +STR_2101 :{WINDOW_COLOUR_2}Pris på Åktursfoto: +STR_2102 :{WINDOW_COLOUR_2}Pris på Åktursfoto: +STR_2103 :{WINDOW_COLOUR_2}Pris på Pretzel: +STR_2104 :{WINDOW_COLOUR_2}Pris på Varm Choklad: +STR_2105 :{WINDOW_COLOUR_2}Pris på Isté: +STR_2106 :{WINDOW_COLOUR_2}Pris på Struva: +STR_2107 :{WINDOW_COLOUR_2}Pris på Solglasögon: +STR_2108 :{WINDOW_COLOUR_2}Pris på Biffnudlar: +STR_2109 :{WINDOW_COLOUR_2}Pris på Stekta Nudlar: +STR_2110 :{WINDOW_COLOUR_2}Pris på Wontonsoppa: +STR_2111 :{WINDOW_COLOUR_2}Pris på Köttbullssoppa: +STR_2112 :{WINDOW_COLOUR_2}Pris på Fruktjuice: +STR_2113 :{WINDOW_COLOUR_2}Pris på Sojamjölk: +STR_2114 :{WINDOW_COLOUR_2}Pris på Sujeonggwa: +STR_2115 :{WINDOW_COLOUR_2}Pris på Macka: +STR_2116 :{WINDOW_COLOUR_2}Pris på Kaka: +STR_2117 :{WINDOW_COLOUR_2} +STR_2118 :{WINDOW_COLOUR_2} +STR_2119 :{WINDOW_COLOUR_2} +STR_2120 :{WINDOW_COLOUR_2}Pris på Ugnskorv: +STR_2121 :{WINDOW_COLOUR_2} +STR_2122 :Åktursfoto +STR_2123 :Åktursfoto +STR_2124 :Åktursfoto +STR_2125 :Pretzel +STR_2126 :Varm Choklad +STR_2127 :Isté +STR_2128 :Struva +STR_2129 :Solglasögon +STR_2130 :Biffnudlar +STR_2131 :Stekta Nudlar +STR_2132 :Wontonsoppa +STR_2133 :Köttbullssoppa +STR_2134 :Fruktjuice +STR_2135 :Sojamjölk +STR_2136 :Sujeonggwa +STR_2137 :Macka +STR_2138 :Kaka +STR_2139 :Tom Skål +STR_2140 :Tomma Tetrapak +STR_2141 :Tom Juiceförpackning +STR_2142 :Ugnskorv +STR_2143 :Tom Skål +STR_2144 :Åktursfoton +STR_2145 :Åktursfoton +STR_2146 :Åktursfoton +STR_2147 :Pretzels +STR_2148 :Muggar Varm Choklad +STR_2149 :Istéer +STR_2150 :Struvor +STR_2151 :Solglasögon +STR_2152 :Biffnudlar +STR_2153 :Friterade Nudlar +STR_2154 :Wontonsoppor +STR_2155 :Köttbullssoppor +STR_2156 :Fruktjuicer +STR_2157 :Glas Sojamjölk +STR_2158 :Sujeonggwas +STR_2159 :Mackor +STR_2160 :Kakor +STR_2161 :Tomma Skålar +STR_2162 :Tomma Tetrapak +STR_2163 :Tomma Juiceförpackningar +STR_2164 :Ugnskorvar +STR_2165 :Tomma Skålar +STR_2166 :ett Åktursfoto +STR_2167 :ett Åktursfoto +STR_2168 :ett Åktursfoto +STR_2169 :en Pretzel +STR_2170 :en Varm Choklad +STR_2171 :en Isté +STR_2172 :en Struva +STR_2173 :ett par Solglasögon +STR_2174 :Biffnudlar +STR_2175 :Stekta Nudlar +STR_2176 :Wontonsoppa +STR_2177 :Köttbullssoppa +STR_2178 :en Fruktjuice +STR_2179 :Sojamjölk +STR_2180 :Sujeonggwa +STR_2181 :en Macka +STR_2182 :en Kaka +STR_2183 :en Tom Skål +STR_2184 :en Tom Tetrapak +STR_2185 :en Tom Juiceförpackning +STR_2186 :en Ugnskorv +STR_2187 :en Tom Skål +STR_2188 :Åktursfoto från {STRINGID} +STR_2189 :Åktursfoto från {STRINGID} +STR_2190 :Åktursfoto från {STRINGID} +STR_2191 :Pretzel +STR_2192 :Varm Choklad +STR_2193 :Isté +STR_2194 :Struva +STR_2195 :Solglasögon +STR_2196 :Biffnudlar +STR_2197 :Stekta Nudlar +STR_2198 :Wontonsoppa +STR_2199 :Köttbollssoppa +STR_2200 :Fruktjuice +STR_2201 :Sojamjölk +STR_2202 :Sujeonggwa +STR_2203 :Macka +STR_2204 :Kaka +STR_2205 :Tom Skål +STR_2206 :Tom Tetrapak +STR_2207 :Tom Juiceförpackning +STR_2208 :Ugnskorv +STR_2209 :Tom Skål +STR_2210 :{SMALLFONT}{BLACK}Visa en lista över alla vaktmästare +STR_2211 :{SMALLFONT}{BLACK}Visa en lista över alla mekaniker +STR_2212 :{SMALLFONT}{BLACK}Visa en lista över alla säkerhetsvakter +STR_2213 :{SMALLFONT}{BLACK}Visa en lista över alla underhållare +STR_2214 :Konstruktion är inte möjligt när spelet är pausat! +STR_2215 :{STRINGID}{NEWLINE}({STRINGID}) +STR_2216 :{WINDOW_COLOUR_2}{COMMA16}{DEGREE}C +STR_2217 :{WINDOW_COLOUR_2}{COMMA16}F +STR_2218 :{RED}{STRINGID} på {STRINGID} har inte kommit tillbaka till {STRINGID} än!{NEWLINE}Kolla om den är fast +STR_2219 :{RED}{COMMA16} personer har dött i en olycka på {STRINGID} +STR_2220 :{WINDOW_COLOUR_2}Parkomdöme: {BLACK}{COMMA16} +STR_2221 :{SMALLFONT}{BLACK}Parkomdöme: {COMMA16} +STR_2222 :{SMALLFONT}{BLACK}{STRINGID} +STR_2223 :{WINDOW_COLOUR_2}Antal gäster: {BLACK}{COMMA16} +STR_2224 :{WINDOW_COLOUR_2}Pengar: {BLACK}{CURRENCY2DP} +STR_2225 :{WINDOW_COLOUR_2}Pengar: {RED}{CURRENCY2DP} +STR_2226 :{WINDOW_COLOUR_2}Parkvärde: {BLACK}{CURRENCY} +STR_2227 :{WINDOW_COLOUR_2}Företagsvärde: {BLACK}{CURRENCY} +STR_2228 :{WINDOW_COLOUR_2}Förra månadens vinst från mat/dricka och{NEWLINE}souvenirer: {BLACK}{CURRENCY} +STR_2229 :Uppförsbacke till vertikalt +STR_2230 :Vertikalt +STR_2231 :Stoppbroms för nedförsbacke +STR_2232 :Upplyftsbacke +STR_2233 :{SMALLFONT}{BLACK}Parkinformation +STR_2234 :Nyliga meddelanden +STR_2235 :{SMALLFONT}{STRINGID} {STRINGID} +STR_2236 :Januari +STR_2237 :Februari +STR_2238 :Mars +STR_2239 :April +STR_2240 :Maj +STR_2241 :Juni +STR_2242 :Juli +STR_2243 :Augusti +STR_2244 :September +STR_2245 :Oktober +STR_2246 :November +STR_2247 :December +STR_2248 :Kan inte riva åktur/attraktion... +STR_2249 :{BABYBLUE}Ny åktur/attraktion är nu tillgänglig:-{NEWLINE}{STRINGID} +STR_2250 :{BABYBLUE}Nya dekorationer/teman är nu tillgängliga:-{NEWLINE}{STRINGID} +STR_2251 :Kan bara byggas på gångvägar! +STR_2252 :Kan bara byggas över gångvägar! +STR_2253 :Transportåkturer +STR_2254 :Lugna Åkturer +STR_2255 :Berg- och Dalbanor +STR_2256 :Spännande Åkturer +STR_2257 :Vattenåkturer +STR_2258 :Affärer & Stånd +STR_2259 :Dekorationer & Teman +STR_2260 :Ingen finansiering +STR_2261 :Minimal finansiering +STR_2262 :Normal finansiering +STR_2263 :Maximal finansiering +STR_2264 :Forskningsfinansiering +STR_2265 :{WINDOW_COLOUR_2}Kostnad: {BLACK}{CURRENCY} per månad +STR_2266 :Forskningsprioriteringar +STR_2267 :Under utveckling +STR_2268 :Tidigare utveckling +STR_2269 :{WINDOW_COLOUR_2}Typ: {BLACK}{STRINGID} +STR_2270 :{WINDOW_COLOUR_2}Status: {BLACK}{STRINGID} +STR_2271 :{WINDOW_COLOUR_2}Slutfört: {BLACK}{STRINGID} +STR_2272 :{WINDOW_COLOUR_2}Åktur/attraktion:{NEWLINE}{BLACK}{STRINGID} +STR_2273 :{WINDOW_COLOUR_2}Dekorationer/teman:{NEWLINE}{BLACK}{STRINGID} +STR_2274 :{SMALLFONT}{BLACK}Visa detaljer kring denna uppfinning eller utveckling +STR_2275 :{SMALLFONT}{BLACK}Visa finansiering och inställningar för forskning & utveckling +STR_2276 :{SMALLFONT}{BLACK}Visa status för forskning och utveckling +STR_2277 :Okänd +STR_2278 :Transportåktur +STR_2279 :Lugn Åktur +STR_2280 :Berg- och Dalbana +STR_2281 :Spännande Åktur +STR_2282 :Vattenåktur +STR_2283 :Affär/Stånd +STR_2284 :Dekorationer/Teman +STR_2285 :Inledande forskning +STR_2286 :Design +STR_2287 :Slutför design +STR_2288 :Okänd +STR_2289 :{STRINGID} {STRINGID} +STR_2290 :{SMALLFONT}{BLACK}{STRINGID} {STRINGID} +STR_2291 :Välj scenario för nytt spel +STR_2292 :{WINDOW_COLOUR_2}har åkt åkturerna: +STR_2293 :{BLACK} Ingenting +STR_2294 :{SMALLFONT}{BLACK}Ändra basterrängens stil +STR_2295 :{SMALLFONT}{BLACK}Ändra vertikala kanter på terrängen +STR_2296 :{BLACK}Betalade {CURRENCY2DP}{WINDOW_COLOUR_2} för att gå in i parken +STR_2297 :{BLACK}Spenderade {CURRENCY2DP}{WINDOW_COLOUR_2} på {BLACK}{COMMA16} åktur +STR_2298 :{BLACK}Spenderade {CURRENCY2DP}{WINDOW_COLOUR_2} på {BLACK}{COMMA16} åkturer +STR_2299 :{BLACK}Spenderade {CURRENCY2DP}{WINDOW_COLOUR_2} på {BLACK}{COMMA16} matprodukt +STR_2300 :{BLACK}Spenderade {CURRENCY2DP}{WINDOW_COLOUR_2} på {BLACK}{COMMA16} matprodukter +STR_2301 :{BLACK}Spenderade {CURRENCY2DP}{WINDOW_COLOUR_2} på {BLACK}{COMMA16} dricka +STR_2302 :{BLACK}Spenderade {CURRENCY2DP}{WINDOW_COLOUR_2} på {BLACK}{COMMA16} drickor +STR_2303 :{BLACK}Spenderade {CURRENCY2DP}{WINDOW_COLOUR_2} på {BLACK}{COMMA16} souvenir +STR_2304 :{BLACK}Spenderade {CURRENCY2DP}{WINDOW_COLOUR_2} på {BLACK}{COMMA16} souvenirer +STR_2305 :Bandesignfiler +STR_2306 :Spara bandesign +STR_2307 :Välj designen {STRINGID} +STR_2308 :{STRINGID} Bandesigns +STR_2309 :Installera ny bandesign +STR_2310 :Bygg egen design +STR_2311 :{WINDOW_COLOUR_2}Glädjenivå: {BLACK}{COMMA2DP32} (approx.) +STR_2312 :{WINDOW_COLOUR_2}Intensitetsnivå: {BLACK}{COMMA2DP32} (approx.) +STR_2313 :{WINDOW_COLOUR_2}Illamåendenivå: {BLACK}{COMMA2DP32} (approx.) +STR_2314 :{WINDOW_COLOUR_2}Åkturslängd: {BLACK}{STRINGID} +STR_2315 :{WINDOW_COLOUR_2}Kostnad: {BLACK}ca {CURRENCY} +STR_2316 :{WINDOW_COLOUR_2}Storlek: {BLACK}{COMMA16} x {COMMA16} blocks +STR_2317 :{WINDOW_COLOUR_2}Ljudkvalitet: +STR_2318 :Låg +STR_2319 :Mellan +STR_2320 :Hög +STR_2321 :{WINDOW_COLOUR_2}Antal åkturer/attraktioner: {BLACK}{COMMA16} +STR_2322 :{WINDOW_COLOUR_2}Personal: {BLACK}{COMMA16} +STR_2323 :{WINDOW_COLOUR_2}Parkstorlek: {BLACK}{COMMA32}m{SQUARED} +STR_2324 :{WINDOW_COLOUR_2}Parkstorlek: {BLACK}{COMMA32}sq.ft. +STR_2325 :{SMALLFONT}{BLACK}Köp land för att utöka parken +STR_2326 :{SMALLFONT}{BLACK}Köp bygglov för att tillåta konstruktion över eller under land utanför parken +STR_2327 :Inställningar +STR_2328 :{WINDOW_COLOUR_2}Valuta: +STR_2329 :{WINDOW_COLOUR_2}Avstånd och Hastighet: +STR_2330 :{WINDOW_COLOUR_2}Temperatur: +STR_2331 :{WINDOW_COLOUR_2}Höjdmarkeringar: +STR_2332 :Enheter +STR_2333 :Ljud +STR_2334 :Pounds ({POUND}) +STR_2335 :Dollar ($) +STR_2336 :Franc (F) +STR_2337 :Deutschmark (DM) +STR_2338 :Yen ({YEN}) +STR_2339 :Peseta (Pts) +STR_2340 :Lira (L) +STR_2341 :Guilders (Dfl.) +STR_2342 :Kronor (kr) +STR_2343 :Euros ({EURO}) +STR_2344 :Brittiska +STR_2345 :Meter +STR_2346 :Visning +STR_2347 :{RED}{STRINGID} har drunknat! +STR_2348 :{SMALLFONT}{BLACK}Visa statistik för personal +STR_2349 :{WINDOW_COLOUR_2}Lön: {BLACK}{CURRENCY} per månad +STR_2350 :{WINDOW_COLOUR_2}Anställd: {BLACK}{MONTHYEAR} +STR_2351 :{WINDOW_COLOUR_2}Klippta gräsmattor: {BLACK}{COMMA16} +STR_2352 :{WINDOW_COLOUR_2}Vattnade trädgårdar: {BLACK}{COMMA16} +STR_2353 :{WINDOW_COLOUR_2}Svepta sopor: {BLACK}{COMMA16} +STR_2354 :{WINDOW_COLOUR_2}Tömda sopkorgar: {BLACK}{COMMA16} +STR_2355 :{WINDOW_COLOUR_2}åkturer fixade: {BLACK}{COMMA16} +STR_2356 :{WINDOW_COLOUR_2}åkturer inspekterade: {BLACK}{COMMA16} +STR_2357 :Hus +STR_2358 :Enheter +STR_2359 :Riktiga Värden +STR_2360 :{WINDOW_COLOUR_2}Skärmupplösning: +STR_2361 :Terrängutjämning +STR_2362 :{SMALLFONT}{BLACK}Sätt på/av terrängkantsutjämning +STR_2363 :Rutmönster på terräng +STR_2364 :{SMALLFONT}{BLACK}Sätt på/av rutmönster på terrängen +STR_2365 :Banken vägrar att utöka ditt lån! +STR_2366 :Celsius ({DEGREE}C) +STR_2367 :Fahrenheit (F) +STR_2368 :Ingen +STR_2369 :Låg +STR_2370 :Mellan +STR_2371 :Hög +STR_2372 :Låg +STR_2373 :Mellan +STR_2374 :Hög +STR_2375 :Väldigt hög +STR_2376 :Exttrem +STR_2377 :Ultra-Extrem +STR_2378 :{SMALLFONT}{BLACK}Justera ett mindre landområde +STR_2379 :{SMALLFONT}{BLACK}Justera ett större landområde +STR_2380 :{SMALLFONT}{BLACK}Justera ett mindre vattenområde +STR_2381 :{SMALLFONT}{BLACK}Justera ett större vattenområde +STR_2382 :Land +STR_2383 :Vatten +STR_2384 :{WINDOW_COLOUR_2}Ditt uppdrag: +STR_2385 :{BLACK}Inget +STR_2386 :{BLACK}Att ha minst {COMMA16} gäster i parken tills {MONTHYEAR}, med ett parkomdöme över 600 +STR_2387 :{BLACK}Att uppnå ett parkvärde över {POP16}{POP16}{CURRENCY} tills {PUSH16}{PUSH16}{PUSH16}{MONTHYEAR} +STR_2388 :{BLACK}Ha Kul! +STR_2389 :{BLACK}Bygg den bästa {STRINGID} du kan! +STR_2390 :{BLACK}Att ha 10 olika sorters berg- och dalbanor i din park, alla med en glädjenivå över 6.00 +STR_2391 :{BLACK}Att ha minst {COMMA16} gäster i din park. Du får inte låta parkomdömet gå under 700! +STR_2392 :{BLACK}Att få en månadsinkomst från åktursbiljetter på minst {POP16}{POP16}{CURRENCY} +STR_2393 :{BLACK}Att ha 10 olika sorters berg- och dalbanor i din park, alla ska vara längre än {LENGTH}, och med en glädjenivå över 7.00 +STR_2394 :{BLACK}Att bygga klart alla 5 delvis byggda berg- och dalbanor i parken, designade så att de alla får en glädjenivå över {POP16}{POP16}{COMMA2DP32} +STR_2395 :{BLACK}Att betala tillbaka ditt lån och uppnå ett parkvärde över {POP16}{POP16}{CURRENCY} +STR_2396 :{BLACK}Att få en månadsinkomst från mat, dricka och souvenirer på minst {POP16}{POP16}{CURRENCY} +STR_2397 :Inga +STR_2398 :Antal gäster vid ett visst datum +STR_2399 :Parkvärde vid ett visst datum +STR_2400 :Ha kul +STR_2401 :Bygg den bästa åkturen du kan +STR_2402 :Bygg 10 berg- och dalbanor +STR_2403 :Antal gäster i parken +STR_2404 :Månadsinkomst från åktursbiljetter +STR_2405 :Bygg 10 berg- och dalbanor med en viss längd +STR_2406 :Bygg klart 5 berg- och dalbanor +STR_2407 :Betala tillbaka lån och uppnå ett visst parkvärde +STR_2408 :Månadsinkomst från mat/souvenirer +STR_2409 :{WINDOW_COLOUR_2}Aktiva kampanjer +STR_2410 :{BLACK}Inga +STR_2411 :{WINDOW_COLOUR_2}Tillgängliga kampanjer +STR_2412 :{SMALLFONT}{BLACK}Påbörja kampanj +STR_2413 :{BLACK}({CURRENCY2DP} per vecka) +STR_2414 :(Ej Vald) +STR_2415 :{WINDOW_COLOUR_2}Åktur: +STR_2416 :{WINDOW_COLOUR_2}Produkt: +STR_2417 :{WINDOW_COLOUR_2}Varaktighet: +STR_2418 :Gratis entré till {STRINGID} +STR_2419 :Gratisåk på {STRINGID} +STR_2420 :Halva priset på entré till {STRINGID} +STR_2421 :Gratis {STRINGID} +STR_2422 :Kampanj för {STRINGID} +STR_2423 :Kampanj för {STRINGID} +STR_2424 :{WINDOW_COLOUR_2}Kuponger för gratis entré till parken +STR_2425 :{WINDOW_COLOUR_2}Kuponger för gratisåk på en specifik åktur +STR_2426 :{WINDOW_COLOUR_2}Kuponger för halva priset på entré till parken +STR_2427 :{WINDOW_COLOUR_2}Kuponger för gratis mat eller dricka +STR_2428 :{WINDOW_COLOUR_2}Kampanj för parken +STR_2429 :{WINDOW_COLOUR_2}Kampanj för en specifik åktur +STR_2430 :{BLACK}Kuponger för gratis entré till {STRINGID} +STR_2431 :{BLACK}Kuponger för gratisåk på {STRINGID} +STR_2432 :{BLACK}Kuponger för halva priset på entré till {STRINGID} +STR_2433 :{BLACK}Kuponger för gratis {STRINGID} +STR_2434 :{BLACK}Kampanj för {STRINGID} +STR_2435 :{BLACK}Kampanj för {STRINGID} +STR_2436 :1 vecka +STR_2437 :2 veckor +STR_2438 :3 veckor +STR_2439 :4 veckor +STR_2440 :5 veckor +STR_2441 :6 veckor +STR_2442 :{BLACK}({STRINGID} återstår) +STR_2443 :{WINDOW_COLOUR_2}Kostnad per vecka: {BLACK}{CURRENCY2DP} +STR_2444 :{WINDOW_COLOUR_2}Totalkostnad: {BLACK}{CURRENCY2DP} +STR_2445 :Starta kampanjen +STR_2446 :{YELLOW}Din kampanj för gratis entré till parken har slutförts +STR_2447 :{YELLOW}Din kampanj för gratis åkturer på {STRINGID} har slutförts +STR_2448 :{YELLOW}Din kampanj för halva priset på entré till parken har slutförts +STR_2449 :{YELLOW}Din kampank för gratis {STRINGID} har slutförts +STR_2450 :{YELLOW}Din kampanj för parken har slutförts +STR_2451 :{YELLOW}Din kampanj för {STRINGID} har slutförts +STR_2452 :{WINDOW_COLOUR_2}Pengar (utan lån): {BLACK}{CURRENCY2DP} +STR_2453 :{WINDOW_COLOUR_2}Pengar (utan lån): {RED}{CURRENCY2DP} +STR_2454 :{SMALLFONT}{BLACK}{CURRENCY2DP} - +STR_2455 :{SMALLFONT}{BLACK}+{CURRENCY2DP} - +STR_2456 :{SMALLFONT}{BLACK}{CURRENCY2DP} - +STR_2457 :{SMALLFONT}{BLACK}Visa finansiella konton +STR_2458 :{SMALLFONT}{BLACK}Visa graf med pengar (utan lån) över tid +STR_2459 :{SMALLFONT}{BLACK}Visa graf med parkvärde över tid +STR_2460 :{SMALLFONT}{BLACK}Visa graf med veckovis vinst +STR_2461 :{SMALLFONT}{BLACK}Visa kampanjer +STR_2462 :{SMALLFONT}{BLACK}Visa parkentrén +STR_2463 :{SMALLFONT}{BLACK}Visa graf med parkomdömen över tid +STR_2464 :{SMALLFONT}{BLACK}Visa graf med gästantal över tid +STR_2465 :{SMALLFONT}{BLACK}Visa parkinträdespris och information +STR_2466 :{SMALLFONT}{BLACK}Visa parkstatistik +STR_2467 :{SMALLFONT}{BLACK}Visa uppdrag +STR_2468 :{SMALLFONT}{BLACK}Visa nyliga utmärkelser som denna park har blivit tilldelad +STR_2469 :{SMALLFONT}{BLACK}Välj nivå på forskning och utveckling +STR_2470 :{SMALLFONT}{BLACK}Forska fram nya transportåkturer +STR_2471 :{SMALLFONT}{BLACK}Forska fram nya lugna åkturer +STR_2472 :{SMALLFONT}{BLACK}Forska fram nya berg- och dalbanor +STR_2473 :{SMALLFONT}{BLACK}Forska fram nya spännande åkturer +STR_2474 :{SMALLFONT}{BLACK}Forska fram nya vattenåkturer +STR_2475 :{SMALLFONT}{BLACK}Forska fram nya affärer och stånd +STR_2476 :{SMALLFONT}{BLACK}Forska fram nya dekorationer and teman +STR_2477 :{SMALLFONT}{BLACK}Välj körläge för denna åktur/attraktion +STR_2478 :{SMALLFONT}{BLACK}Visa graf med hastighet över tid +STR_2479 :{SMALLFONT}{BLACK}Visa graf med höjd över tid +STR_2480 :{SMALLFONT}{BLACK}Visa graf med vertikal acceleration över tid +STR_2481 :{SMALLFONT}{BLACK}Visa graf med lateral acceleration över tid +STR_2482 :{SMALLFONT}{BLACK}Vinst: {CURRENCY} per vecka, Parkvärde: {CURRENCY} +STR_2483 :{WINDOW_COLOUR_2}Veckovis vinst: {BLACK}+{CURRENCY2DP} +STR_2484 :{WINDOW_COLOUR_2}Veckovis vinst: {RED}{CURRENCY2DP} +STR_2485 :Kontroller +STR_2486 :Allmänt +STR_2487 :Visa 'riktiga' namn på gäster +STR_2488 :{SMALLFONT}{BLACK}Byt mellan 'riktiga' namn och gästnummer +STR_2489 :Snabbtangenter... +STR_2490 :Snabbtangenter +STR_2491 :Återställ snabbtangenter +STR_2492 :{SMALLFONT}{BLACK}Återställ alla snabbtangenter till standardinställningar +STR_2493 :Stäng fönstret som är längst fram +STR_2494 :Stäng alla fönster +STR_2495 :Avbryt konstruktionsläget +STR_2496 :Pausa spelet +STR_2497 :Zooma ut +STR_2498 :Zooma in +STR_2499 :Rotera vyn +STR_2500 :Rotera konstruktionsobjektet +STR_2501 :Underjordsvy +STR_2502 :Dölj terräng +STR_2503 :Dölj vertikal terräng +STR_2504 :Genomskinliga åkturer +STR_2505 :Genomskinliga dekorationer +STR_2506 :Dölj stödpelare +STR_2507 :Dölj besökare +STR_2508 :Höjdmarkeringar på terräng +STR_2509 :Höjdmarkeringar på åktursbanor +STR_2510 :Höjdmarkeringar på gångvägar +STR_2511 :Justera land +STR_2512 :Justera vatten +STR_2513 :Bygg dekorationer +STR_2514 :Bygg gångvägar +STR_2515 :Bygg ny åktur +STR_2516 :Visa finansiell information +STR_2517 :Visa forskningsinformation +STR_2518 :Visa lista över åkturer +STR_2519 :Visa parkinformation +STR_2520 :Visa gästlista +STR_2521 :Visa personallista +STR_2522 :Visa nyliga meddelanden +STR_2523 :Visa karta +STR_2524 :Skärmdump +STR_2525 :??? +STR_2526 :??? +STR_2527 :??? +STR_2528 :??? +STR_2529 :??? +STR_2530 :??? +STR_2531 :??? +STR_2532 :??? +STR_2533 :Backspace +STR_2534 :Tab +STR_2535 :??? +STR_2536 :??? +STR_2537 :Clear +STR_2538 :Return +STR_2539 :??? +STR_2540 :??? +STR_2541 :??? +STR_2542 :??? +STR_2543 :Alt/Menu +STR_2544 :Pause +STR_2545 :Caps +STR_2546 :??? +STR_2547 :??? +STR_2548 :??? +STR_2549 :??? +STR_2550 :??? +STR_2551 :??? +STR_2552 :Escape +STR_2553 :??? +STR_2554 :??? +STR_2555 :??? +STR_2556 :??? +STR_2557 :Mellanslag +STR_2558 :PgUp +STR_2559 :PgDn +STR_2560 :End +STR_2561 :Home +STR_2562 :Vänster +STR_2563 :Upp +STR_2564 :Höger +STR_2565 :Ner +STR_2566 :Select +STR_2567 :Print +STR_2568 :Execute +STR_2569 :Snapshot +STR_2570 :Insert +STR_2571 :Delete +STR_2572 :Help +STR_2573 :0 +STR_2574 :1 +STR_2575 :2 +STR_2576 :3 +STR_2577 :4 +STR_2578 :5 +STR_2579 :6 +STR_2580 :7 +STR_2581 :8 +STR_2582 :9 +STR_2583 :??? +STR_2584 :??? +STR_2585 :??? +STR_2586 :??? +STR_2587 :??? +STR_2588 :??? +STR_2589 :??? +STR_2590 :A +STR_2591 :B +STR_2592 :C +STR_2593 :D +STR_2594 :E +STR_2595 :F +STR_2596 :G +STR_2597 :H +STR_2598 :I +STR_2599 :J +STR_2600 :K +STR_2601 :L +STR_2602 :M +STR_2603 :N +STR_2604 :O +STR_2605 :P +STR_2606 :Q +STR_2607 :R +STR_2608 :S +STR_2609 :T +STR_2610 :U +STR_2611 :V +STR_2612 :W +STR_2613 :X +STR_2614 :Y +STR_2615 :Z +STR_2616 :??? +STR_2617 :??? +STR_2618 :Menu +STR_2619 :??? +STR_2620 :??? +STR_2621 :NumPad 0 +STR_2622 :NumPad 1 +STR_2623 :NumPad 2 +STR_2624 :NumPad 3 +STR_2625 :NumPad 4 +STR_2626 :NumPad 5 +STR_2627 :NumPad 6 +STR_2628 :NumPad 7 +STR_2629 :NumPad 8 +STR_2630 :NumPad 9 +STR_2631 :NumPad * +STR_2632 :NumPad + +STR_2633 :??? +STR_2634 :NumPad - +STR_2635 :NumPad . +STR_2636 :NumPad / +STR_2637 :F1 +STR_2638 :F2 +STR_2639 :F3 +STR_2640 :F4 +STR_2641 :F5 +STR_2642 :F6 +STR_2643 :F7 +STR_2644 :F8 +STR_2645 :F9 +STR_2646 :F10 +STR_2647 :F11 +STR_2648 :F12 +STR_2649 :F13 +STR_2650 :F14 +STR_2651 :F15 +STR_2652 :F16 +STR_2653 :F17 +STR_2654 :F18 +STR_2655 :F19 +STR_2656 :F20 +STR_2657 :F21 +STR_2658 :F22 +STR_2659 :F23 +STR_2660 :F24 +STR_2661 :??? +STR_2662 :??? +STR_2663 :??? +STR_2664 :??? +STR_2665 :??? +STR_2666 :??? +STR_2667 :??? +STR_2668 :??? +STR_2669 :NumLock +STR_2670 :Scroll +STR_2671 :??? +STR_2672 :??? +STR_2673 :??? +STR_2674 :??? +STR_2675 :??? +STR_2676 :??? +STR_2677 :??? +STR_2678 :??? +STR_2679 :??? +STR_2680 :??? +STR_2681 :??? +STR_2682 :??? +STR_2683 :??? +STR_2684 :??? +STR_2685 :??? +STR_2686 :??? +STR_2687 :??? +STR_2688 :??? +STR_2689 :??? +STR_2690 :??? +STR_2691 :??? +STR_2692 :??? +STR_2693 :??? +STR_2694 :??? +STR_2695 :??? +STR_2696 :??? +STR_2697 :??? +STR_2698 :??? +STR_2699 :??? +STR_2700 :??? +STR_2701 :??? +STR_2702 :??? +STR_2703 :??? +STR_2704 :??? +STR_2705 :??? +STR_2706 :??? +STR_2707 :??? +STR_2708 :??? +STR_2709 :??? +STR_2710 :??? +STR_2711 :; +STR_2712 := +STR_2713 :, +STR_2714 :- +STR_2715 :. +STR_2716 :/ +STR_2717 :' +STR_2718 :??? +STR_2719 :??? +STR_2720 :??? +STR_2721 :??? +STR_2722 :??? +STR_2723 :??? +STR_2724 :??? +STR_2725 :??? +STR_2726 :??? +STR_2727 :??? +STR_2728 :??? +STR_2729 :??? +STR_2730 :??? +STR_2731 :??? +STR_2732 :??? +STR_2733 :??? +STR_2734 :??? +STR_2735 :??? +STR_2736 :??? +STR_2737 :??? +STR_2738 :??? +STR_2739 :??? +STR_2740 :??? +STR_2741 :??? +STR_2742 :??? +STR_2743 :??? +STR_2744 :[ +STR_2745 :\ +STR_2746 :] +STR_2747 :{ENDQUOTES} +STR_2748 :Bar +STR_2749 :??? +STR_2750 :??? +STR_2751 :??? +STR_2752 :??? +STR_2753 :??? +STR_2754 :??? +STR_2755 :??? +STR_2756 :??? +STR_2757 :??? +STR_2758 :??? +STR_2759 :??? +# New strings used in the cheats window previously these were ??? +STR_2760 :+5K Pengar +STR_2761 :Betala För Entré +STR_2762 :Betala För Åkturer +STR_2763 :??? +STR_2764 :Glada Gäster +STR_2765 :Stort Tåg +STR_2766 :??? +STR_2767 :Frys Klimat +STR_2768 :Avfrys klimat +STR_2769 :Öppna Park +STR_2770 :Stäng Park +STR_2771 :Långsammare Spekhastighet +STR_2772 :Snabbare Spelhastighet +STR_2773 :Fönster +STR_2774 :Fullskärm +STR_2775 :Fullskärm (skrivbord) +STR_2776 :Språk +STR_2777 :{MOVE_X}{SMALLFONT}{STRING} +STR_2778 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRING} +# End of new strings +STR_2779 :??? +STR_2780 :??? +STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID}{STRINGID} +STR_2782 :SHIFT + +STR_2783 :CTRL + +STR_2784 :Ändra snabbtangenter +STR_2785 :{WINDOW_COLOUR_2}Välj ny snabbtangent för:-{NEWLINE}{OPENQUOTES}{STRINGID}{ENDQUOTES} +STR_2786 :{SMALLFONT}{BLACK}Klicka på en beskrivning för att välja en ny snabbtangent +STR_2787 :{WINDOW_COLOUR_2}Parkvärde: {BLACK}{CURRENCY} +STR_2788 :{WINDOW_COLOUR_2}Grattis !{NEWLINE}{BLACK}Du uppnådde ditt mål med ett företagsvärde på {CURRENCY} ! +STR_2789 :{WINDOW_COLOUR_2}Du har misslyckats med ditt mål ! +#TODO, scenario chart? +STR_2790 :Skriv in namn i scenario chart +STR_2791 :Skriv in namn +#TODO +STR_2792 :Var god skriv in ditt namn i scenario chart:- +STR_2793 :{SMALLFONT}(Avklarad av {STRINGID}) +STR_2794 :{WINDOW_COLOUR_2}Avklarad av: {BLACK}{STRINGID}{NEWLINE}{WINDOW_COLOUR_2} med ett företagsvärde på: {BLACK}{CURRENCY} +STR_2795 :Sortera +STR_2796 :{SMALLFONT}{BLACK}Sortera åkturslistan i ordning enligt den valda informationstypen +STR_2797 :Flytta vyn när muspekaren är vid skärmens kant +STR_2798 :{SMALLFONT}{BLACK}Välj om vyn ska förflyttas när muspekaren är vid skärmens kant +STR_2799 :{SMALLFONT}{BLACK}Visa eller ändra kontrolltangentstilldelningar +STR_2800 :{WINDOW_COLOUR_2}Totalt antal inträden: {BLACK}{COMMA32} +STR_2801 :{WINDOW_COLOUR_2}Inkomst från inträden: {BLACK}{CURRENCY2DP} +STR_2802 :Karta +STR_2803 :{SMALLFONT}{BLACK}Markera dessa gäster på kartan +STR_2804 :{SMALLFONT}{BLACK}Markera denna personal på kartan +STR_2805 :{SMALLFONT}{BLACK}Visa karta över parken +STR_2806 :{RED}Gäster klagar på gångvägarnas snuskiga tillstånd{NEWLINE}Kolla var dina vaktmästare är och överväg att organisera dom bättre +STR_2807 :{RED}Gäster klagar på mängden skräp i din park{NEWLINE}Kolla var dina vaktmästare är och överväg att organisera dom bättre +STR_2808 :{RED}Gäster klagar på vandalismen i din park{NEWLINE}Kolla var dina säkerhetsvakter är och överväg att organisera dom bättre +STR_2809 :{RED}Gäster är hungriga och kan inte hitta någonstans att köpa mat +STR_2810 :{RED}Gäster är törstiga och kan inte hitta någonstans att köpa dricka +STR_2811 :{RED}Gäster klagar för att dom inte kan hitta toaletterna i din park +STR_2812 :{RED}Gäster tappar bort sig eller fastnar{NEWLINE}Kolla om din vägplaneringar behöver förbättras för att hjälpa gästerna att hitta +STR_2813 :{RED}Ditt parkinträde är för dyrt!{NEWLINE}Sänk ditt inträde eller höj värdet på parken för att attrahera fler gäster +STR_2814 :{WINDOW_COLOUR_2}Utmärkelse för mest ostädade park +STR_2815 :{WINDOW_COLOUR_2}Utmärkelse för mest välstädade park +STR_2816 :{WINDOW_COLOUR_2}Utmärkelse för parken med bäst berg- och dalbanor +STR_2817 :{WINDOW_COLOUR_2}Utmärkelse för mest värda park +STR_2818 :{WINDOW_COLOUR_2}Utmärkelse för vackraste parken +STR_2819 :{WINDOW_COLOUR_2}Utmärkelse för mest ovärda park +STR_2820 :{WINDOW_COLOUR_2}Utmärkelse för säkraste parken +STR_2821 :{WINDOW_COLOUR_2}Utmärkelse för bästa personal +STR_2822 :{WINDOW_COLOUR_2}Utmärkelse för bästa maten +STR_2823 :{WINDOW_COLOUR_2}Utmärkelse för sämsta maten +STR_2824 :{WINDOW_COLOUR_2}Utmärkelse för bästa toaletterna +STR_2825 :{WINDOW_COLOUR_2}Utmärkelse för mest besvikna gäster +STR_2826 :{WINDOW_COLOUR_2}Utmärkelse för bästa vattenåkturer +STR_2827 :{WINDOW_COLOUR_2}Utmärkelse för bästa egendesignade åkturer +STR_2828 :{WINDOW_COLOUR_2}Utmärkelse för finast färger på åkturer +STR_2829 :{WINDOW_COLOUR_2}Utmärkelse för mest förvirrande vägplanering +STR_2830 :{WINDOW_COLOUR_2}Utmärkelse för mest lugna åktur +STR_2831 :{TOPAZ}Din park har fått en utmärkelse för 'Den mest ostädade parken i landet'! +STR_2832 :{TOPAZ}Din park har fått en utmärkelse för 'Den mest välstädade parken i landet'! +STR_2833 :{TOPAZ}Din park har fått en utmärkelse för 'Parken med bäst berg- och dalbanor'! +STR_2834 :{TOPAZ}Din park har fått en utmärkelse för 'Den mest värda parken i landet'! +STR_2835 :{TOPAZ}Din park har fått en utmärkelse för 'Den vackraste parken i landet'! +STR_2836 :{TOPAZ}Din park har fått en utmärkelse för 'Den mest ovärda parken i landet'! +STR_2837 :{TOPAZ}Din park har fått en utmärkelse för 'Den säkraste parken i landet'! +STR_2838 :{TOPAZ}Din park har fått en utmärkelse för 'Parken med bäst personal'! +STR_2839 :{TOPAZ}Din park har fått en utmärkelse för 'Parken med bäst mat i landet'! +STR_2840 :{TOPAZ}Din park har fått en utmärkelse för 'Parken med sämst mat i landet'! +STR_2841 :{TOPAZ}Din park har fått en utmärkelse för 'Parken med bäst toaletter i landet'! +STR_2842 :{TOPAZ}Din park har fått en utmärkelse för 'Parken med mest besvikna gäster i landet'! +STR_2843 :{TOPAZ}Din park har fått en utmärkelse för 'Parken med bäst vattenåkturer i landet'! +STR_2844 :{TOPAZ}Din park har fått en utmärkelse för 'Parken med bäst egendesignade åkturer'! +STR_2845 :{TOPAZ}Din park har fått en utmärkelse för 'Parken med finast färgval på åkturer'! +STR_2846 :{TOPAZ}Din park har fått en utmärkelse för 'Parken med mest förvirrande vägplanering'! +STR_2847 :{TOPAZ}Din park har fått en utmärkelse för 'Parken med bäst lugna åkturer'! +STR_2848 :{WINDOW_COLOUR_2}Inga nyliga utmärkelser +STR_2849 :Nytt scenario installerat +STR_2850 :Ny bandesign installerad +STR_2851 :Scenario redan installerat +STR_2852 :Bandesign redan installerad +STR_2853 :Förbjuden av lokala myndigheter! +STR_2854 :{RED}Gästar kan inte komma fram till ingången till {STRINGID} !{NEWLINE}Bygg en gångväg till ingången +STR_2855 :{RED}{STRINGID} har ingen gångväg från sin utgång !{NEWLINE}Bygg en gångväg från åkturens utgång +STR_2856 :{WINDOW_COLOUR_2}Handledning +STR_2857 :{WINDOW_COLOUR_2}(Tryck ner en tangent eller musknapp för att ta kontroll) +STR_2858 :Kan inte påbörja kampanj... +STR_2859 :En annan instans av RollerCoaster Tycoon 2 körs redan +STR_2860 :Om Infogrames Interactive... +STR_2861 :{WINDOW_COLOUR_2}Licensed to Infogrames Interactive Inc. +STR_2862 :Om Musik... +STR_2863 :Om Musik +STR_2864 :{WINDOW_COLOUR_2}March - Children of the Regiment: (Fucik) non copyright +STR_2865 :{WINDOW_COLOUR_2}Heyken's Serenade: (J.Heyken) British Standard Music Coy; GEMA, BRITICO +STR_2866 :{WINDOW_COLOUR_2}In Continental Mood: (Composer unknown) Copyright Control +STR_2867 :{WINDOW_COLOUR_2}Wedding Journey: (Traditional) +STR_2868 :{WINDOW_COLOUR_2}Tales from the Vienna Woods: (Johann Strauss) non copyright +STR_2869 :{WINDOW_COLOUR_2}Slavonic Dance: (Traditional) +STR_2870 :{WINDOW_COLOUR_2}Das Alpenhorn: (Traditional) +STR_2871 :{WINDOW_COLOUR_2}The Blond Sailor: (Traditional) +STR_2872 :{WINDOW_COLOUR_2}Overture - Poet and Peasant: (Suppe) non copyright +STR_2873 :{WINDOW_COLOUR_2}Waltz Medley: (Johann Strauss) non copyright +STR_2874 :{WINDOW_COLOUR_2}Bella Bella Bimba: (Traditional) +STR_2875 :{WINDOW_COLOUR_2}Original recordings (P) 1976 C.J.Mears Organization, used with consent +STR_2876 :{WINDOW_COLOUR_2}RollerCoaster Tycoon 2 Title Music: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2877 :{WINDOW_COLOUR_2}Dodgems Beat: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2878 :{WINDOW_COLOUR_2}Mid Summer's Heat: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2879 :{WINDOW_COLOUR_2}Pharaoh's Tomb: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2880 :{WINDOW_COLOUR_2}Caesar's March: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2881 :{WINDOW_COLOUR_2}Drifting To Heaven: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2882 :{WINDOW_COLOUR_2}Invaders: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2883 :{WINDOW_COLOUR_2}Eternal Toybox: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2884 :{WINDOW_COLOUR_2}Jungle Juice: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2885 :{WINDOW_COLOUR_2}Ninja's Noodles: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2886 :{WINDOW_COLOUR_2}Voyage to Andromeda: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2887 :{WINDOW_COLOUR_2}Brimble's Beat: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2888 :{WINDOW_COLOUR_2}Atlantis: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2889 :{WINDOW_COLOUR_2}Wild West Kid: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2890 :{WINDOW_COLOUR_2}Vampire's Lair: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2891 :{WINDOW_COLOUR_2}Blockbuster: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2892 :{WINDOW_COLOUR_2}Airtime Rock: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2893 :{WINDOW_COLOUR_2}Searchlight Rag: (Scott Joplin/Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2894 :{WINDOW_COLOUR_2}Flight of Fantasy: (Steve Blenkinsopp) copyright {COPYRIGHT} Chris Sawyer +STR_2895 :{WINDOW_COLOUR_2}Big Rock: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2896 :{WINDOW_COLOUR_2}Hypothermia: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2897 :{WINDOW_COLOUR_2}Last Sleigh Åktur: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2898 :{WINDOW_COLOUR_2}Pipes of Glencairn: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2899 :{WINDOW_COLOUR_2}Traffic Jam: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2900 :{WINDOW_COLOUR_2} +STR_2901 :{WINDOW_COLOUR_2}(Samples courtesy of Spectrasonics {ENDQUOTES}Liquid Grooves{ENDQUOTES}) +STR_2902 :{WINDOW_COLOUR_2}Toccata: (C.M.Widor, played by Peter James Adcock) recording {COPYRIGHT} Chris Sawyer +STR_2903 :{WINDOW_COLOUR_2}Space Rock: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2904 :{WINDOW_COLOUR_2}Manic Mechanic: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2905 :{WINDOW_COLOUR_2}Techno Torture: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2906 :{WINDOW_COLOUR_2}Sweat Dreams: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2907 :{WINDOW_COLOUR_2}What shall we do with the Drunken Sailor: (Anon/Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2908 :{WINDOW_COLOUR_2}Infogrames Interactive +STR_2909 :{WINDOW_COLOUR_2}Senior Producer: Thomas J. Zahorik +STR_2910 :{WINDOW_COLOUR_2}Executive Producer: Bill Levay +STR_2911 :{WINDOW_COLOUR_2}Senior Marketing Product Manager: Scott Triola +STR_2912 :{WINDOW_COLOUR_2}V.P. of Product Development: Scott Walker +STR_2913 :{WINDOW_COLOUR_2}General Manager: John Hurlbut +STR_2914 :{WINDOW_COLOUR_2}Director of Quality Assurance: Michael Craighead +STR_2915 :{WINDOW_COLOUR_2}Q.A. Certification Manager: Kurt Boutin +STR_2916 :{WINDOW_COLOUR_2}Q.A. Certification Lead: Mark Huggins +STR_2917 :{WINDOW_COLOUR_2}Testers: Dena Irene Fitzgerald, Scott Rollins, Christopher McPhail +STR_2918 :{WINDOW_COLOUR_2}Clif McClure, Erik Maramaldi, Erik Jeffery +STR_2919 :{WINDOW_COLOUR_2}Director of Marketing: Ann Marie Bland +STR_2920 :{WINDOW_COLOUR_2}Manager of Creative Services: Steve Martin +STR_2921 :{WINDOW_COLOUR_2}Manager of Editorial & Documentation Services: Elizabeth Mackney +STR_2922 :{WINDOW_COLOUR_2}Graphic Designer: Paul Anselmi +STR_2923 :{WINDOW_COLOUR_2}Copywriter: Kurt Carlson +STR_2924 :{WINDOW_COLOUR_2}Special Thanks to: Peter Matiss +STR_2925 :{WINDOW_COLOUR_2}Engineering Specialist: Ken Edwards +STR_2926 :{WINDOW_COLOUR_2}Engineering Services Manager: Luis Rivas +STR_2927 :{WINDOW_COLOUR_2}Lead Compatibility Analyst: Geoffrey Smith +STR_2928 :{WINDOW_COLOUR_2}Compatibility Analysts: Jason Cordero, Burke McQuinn, Kim Jardin +STR_2929 :{WINDOW_COLOUR_2}Lead Tester: Daniel Frisoli +STR_2930 :{WINDOW_COLOUR_2}Senior Tester: Matt Pantaleoni +STR_2931 :{WINDOW_COLOUR_2} +STR_2932 :{WINDOW_COLOUR_2} +STR_2933 :{WINDOW_COLOUR_2} +STR_2934 :{WINDOW_COLOUR_2} +STR_2935 :{WINDOW_COLOUR_2} +STR_2936 :{WINDOW_COLOUR_2} +STR_2937 :{WINDOW_COLOUR_2} +STR_2938 :{WINDOW_COLOUR_2} +STR_2939 :{WINDOW_COLOUR_2} +STR_2940 :{WINDOW_COLOUR_2} +STR_2941 :{WINDOW_COLOUR_2} +STR_2942 :{WINDOW_COLOUR_2} +STR_2943 :{WINDOW_COLOUR_2} +STR_2944 :{WINDOW_COLOUR_2} +STR_2945 :{WINDOW_COLOUR_2} +STR_2946 :{WINDOW_COLOUR_2} +STR_2947 :{WINDOW_COLOUR_2} +STR_2948 :{WINDOW_COLOUR_2} +STR_2949 :{WINDOW_COLOUR_2} +STR_2950 :{WINDOW_COLOUR_2} +STR_2951 :{WINDOW_COLOUR_2} +STR_2952 :{WINDOW_COLOUR_2} +STR_2953 :{WINDOW_COLOUR_2} +STR_2954 :{WINDOW_COLOUR_2} +STR_2955 :{WINDOW_COLOUR_2} +STR_2956 :{WINDOW_COLOUR_2} +STR_2957 :{WINDOW_COLOUR_2} +STR_2958 :{WINDOW_COLOUR_2} +STR_2959 :{WINDOW_COLOUR_2} +STR_2960 :{WINDOW_COLOUR_2} +STR_2961 :{WINDOW_COLOUR_2} +STR_2962 :{WINDOW_COLOUR_2} +STR_2963 :{WINDOW_COLOUR_2} +STR_2964 :{WINDOW_COLOUR_2} +STR_2965 :{WINDOW_COLOUR_2} +STR_2966 : +STR_2967 : +STR_2968 : +STR_2969 :Use of this product is subject to the terms of a license agreement +STR_2970 :found in the product's {OPENQUOTES}ReadMe{ENDQUOTES} file and in the manual +STR_2971 :Huvudfärg +STR_2972 :Andra färg +STR_2973 :Tredje färg +STR_2974 :Fjärde färg +STR_2975 :{SMALLFONT}{BLACK}Välj vilken färgpalett som ska ändras eller användas för målning av en åktur +STR_2976 :{SMALLFONT}{BLACK}Måla ett enstaka område på denna åktur med den valda färgpaletten +STR_2977 :Personalnamn +STR_2978 :Skriv in nytt namn på personal:- +STR_2979 :Kan inte namnge personal... +STR_2980 :För många banderoller i spelet +STR_2981 :{RED}Tillträde förbjudet - - +STR_2982 :Banderolltext +STR_2983 :Skriv in ny text för denna banderoll:- +STR_2984 :Kan inte sätta ny text på banderollen... +STR_2985 :Banderoll +STR_2986 :{SMALLFONT}{BLACK}Byt text på banderoll +STR_2987 :{SMALLFONT}{BLACK}Sätt denna banderoll som en 'Tillträde förbjudet'-banderoll för gäster +STR_2988 :{SMALLFONT}{BLACK}Riv denna banderoll +STR_2989 :{SMALLFONT}{BLACK}Välj huvudfärg +STR_2990 :{SMALLFONT}{BLACK}Välj textfärg +STR_2991 :Banderoll +STR_2992 :Skylttext +STR_2993 :Skriv in ny text för denna skylt:- +STR_2994 :{SMALLFONT}{BLACK}Byt text på skylt +STR_2995 :{SMALLFONT}{BLACK}Riv denna skylt +STR_2996 :{BLACK}ABC +STR_2997 :{GREY}ABC +STR_2998 :{WHITE}ABC +STR_2999 :{RED}ABC +STR_3000 :{GREEN}ABC +STR_3001 :{YELLOW}ABC +STR_3002 :{TOPAZ}ABC +STR_3003 :{CELADON}ABC +STR_3004 :{BABYBLUE}ABC +STR_3005 :{PALELAVENDER}ABC +STR_3006 :{PALEGOLD}ABC +STR_3007 :{LIGHTPINK}ABC +STR_3008 :{PEARLAQUA}ABC +STR_3009 :{PALESILVER}ABC +STR_3010 :Kan inte ladda fil... +STR_3011 :Filen innehåller ogiltig data +STR_3012 :Dodgems beat-stil +STR_3013 :Marknadsplatsorgel-stil +STR_3014 :Romersk stil +STR_3015 :Orientalisk stil +STR_3016 :Marsiansk stil +STR_3017 :Jungeltrumme-stil +STR_3018 :Egyptisk stil +STR_3019 :Leksakslands-stil +STR_3020 : +STR_3021 :Rymd-stil +STR_3022 :Skräck-stil +STR_3023 :Techno-stil +STR_3024 :Lugn stil +STR_3025 :Sommar-stil +STR_3026 :Vatten-stil +STR_3027 :Vilda västern-stil +STR_3028 :Jurassic-stil +STR_3029 :Rock-stil +STR_3030 :Ragtime-stil +STR_3031 :Fantasi-stil +STR_3032 :Rock-stil 2 +STR_3033 :Is-stil +STR_3034 :Snö-stil +STR_3035 :Egen musik 1 +STR_3036 :Egen musik 2 +STR_3037 :Medeltids-stil +STR_3038 :Stads-stil +STR_3039 :Orgel-stil +STR_3040 :Mekanisk-stil +STR_3041 :Modern-stil +STR_3042 :Pirat-stil +STR_3043 :Rock-stil 3 +STR_3044 :Godis-stil +STR_3045 :{SMALLFONT}{BLACK}Välj musikstil som ska spelas +STR_3046 :Denna åktur kan inte modifieras +STR_3047 :Lokala myndigheter har förbjudit rivning och modifikation av denna Åktur +STR_3048 :Kampanjer är förbjudna av lokala myndigheter +STR_3049 :Golfhål A +STR_3050 :Golfhål B +STR_3051 :Golfhål C +STR_3052 :Golfhål D +STR_3053 :Golfhål E +STR_3054 :Laddar... +STR_3055 :Vit +STR_3056 :Genomskinlig +STR_3057 :{WINDOW_COLOUR_2}Konstruktionsmarkör: +STR_3058 :Tegelstensväggar +STR_3059 :Häckar +STR_3060 :Isblock +STR_3061 :Trästaket +STR_3062 :{SMALLFONT}{BLACK}Standard berg- och dalbane-spår +STR_3063 :{SMALLFONT}{BLACK}Vattenkanal (spår under vatten) +STR_3064 :Nybörjarparker +STR_3065 :Utmanande Parker +STR_3066 :Expertparker +STR_3067 :{OPENQUOTES}Riktiga{ENDQUOTES} Parker +STR_3068 :Andra Parker +STR_3069 :Toppsektion +STR_3070 :Sluttning till platt +STR_3071 :{WINDOW_COLOUR_2}Samma pris genom parken +STR_3072 :{SMALLFONT}{BLACK}Välj om det här priset ska användas genom hela parken +STR_3073 :{RED}VARNING: Ditt parkomdöme har gått under 700 !{NEWLINE}Om du inte har höjt parkomdömet inom 4 veckor kommer din park att stängas +STR_3074 :{RED}VARNING: Ditt parkomdöme är fortfarande under 700 !{NEWLINE}Du har 3 veckor på dig att höja parkomdömet +STR_3075 :{RED}VARNING: Ditt parkomdöme är fortfarande under 700 !{NEWLINE}Du har bara 2 veckor på dig att höja parkomdömet, annars kommer din park att stängas +STR_3076 :{RED}SISTA VARNING: Ditt parkomdöme är fortfarande under 700 !{NEWLINE}Om bara 7 dagar kommer din park att stängas om du inte kan höja parkomdömet +STR_3077 :{RED}STÄNGNINGSNOTIS: Din park har blivit stängd ! +STR_3078 :Vanlig ingång +STR_3079 :Träingång +STR_3080 :Tältingång +STR_3081 :Slottsingång (grå) +STR_3082 :Slottsingång (brun) +STR_3083 :Jungelingång +STR_3084 :Timmerstugeingång +STR_3085 :Klassisk/romersk ingång +STR_3086 :Abstrakt ingång +STR_3087 :Snö/is-ingång +STR_3088 :Pagodaingång +STR_3089 :Rymdingång +STR_3090 :{SMALLFONT}{BLACK}Välj stil för ingången, utgången och stationen +STR_3091 :Du får inte ta bort den här sektionen! +STR_3092 :Du får inte flytta eller modifiera stationen för den här åkturen! +STR_3093 :{WINDOW_COLOUR_2}Favorit: {BLACK}{STRINGID} +STR_3094 :N/A +STR_3095 :{WINDOW_COLOUR_2}Upplyftskedjehastighet: +STR_3096 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{VELOCITY} +STR_3097 :{SMALLFONT}{BLACK}Välj upplyftskedjehastighet +STR_3098 :Kan inte byta upplyftskedjehastighet... +STR_3099 :{SMALLFONT}{BLACK}Välj huvudfärg +STR_3100 :{SMALLFONT}{BLACK}Välj andra färg +STR_3101 :{SMALLFONT}{BLACK}Välj tredje färg +STR_3102 :{SMALLFONT}{BLACK}Måla om färgade dekorationer +STR_3103 :Kan inte måla om detta... +STR_3104 :{SMALLFONT}{BLACK}Lista åkturer +STR_3105 :{SMALLFONT}{BLACK}Lista affärer och stånd +STR_3106 :{SMALLFONT}{BLACK}Lista informationskiosker och andra gästfaciliteter +STR_3107 :Stäng +STR_3108 :Testa +STR_3109 :Öppna +STR_3110 :{WINDOW_COLOUR_2}Blocksektioner: {BLACK}{COMMA16} +STR_3111 :{SMALLFONT}{BLACK}Klicka på en design för att bygga den +STR_3112 :{SMALLFONT}{BLACK}Klicka på en design för att byta namn eller ta bort den +STR_3113 :Välj en annan design +STR_3114 :{SMALLFONT}{BLACK}Gå tillbaka till menyn för att välja design +STR_3115 :{SMALLFONT}{BLACK}Spara bandesign +STR_3116 :{SMALLFONT}{BLACK}Spara bandesign (Inte möjligt innan åkturen har blivit testad och statistik har genererats) +STR_3117 :{BLACK}Ringer mekaniker... +STR_3118 :{BLACK}{STRINGID} är på väg till åkturen +STR_3119 :{BLACK}{STRINGID} fixar åkturen +STR_3120 :{SMALLFONT}{BLACK}Hitta närmsta tillgängliga mekaniker, eller mekanikern som fixar åkturen +STR_3121 :Kan inte hitta en mekaniker, eller så är alla i närheten upptagna +STR_3122 :{BLACK}{COMMA16} gästs {WINDOW_COLOUR_2}favoritåktur +STR_3123 :{BLACK}{COMMA16} gästers {WINDOW_COLOUR_2}favoritåktur +STR_3124 :Trasig {STRINGID} +STR_3125 :{WINDOW_COLOUR_2}Glädjefaktor: {BLACK}+{COMMA16}% +STR_3126 :{WINDOW_COLOUR_2}Intensitetsfaktor: {BLACK}+{COMMA16}% +STR_3127 :{WINDOW_COLOUR_2}Illamåendefaktor: {BLACK}+{COMMA16}% +STR_3128 :Spara Bandesign +STR_3129 :Spara Bandesign med Dekorationer +STR_3130 :Spara +STR_3131 :Avbryt +STR_3132 :{BLACK}Klicka på dekorationer för att markera dom för sparning med bandesignen... +STR_3133 :Kan inte bygga detta på en sluttning +STR_3134 :{RED}(Designen inkluderar dekorationer som är otillgängliga) +STR_3135 :{RED}(Fordonstyp otillgänglig - Åktursbeteende kan påverkas) +STR_3136 :Varning: Denna design kommer att byggas med en alternativ fordonstyp och kanske inte beter sig som väntat +STR_3137 :Välj Närliggande Dekorationer +STR_3138 :Återställ Markering +STR_3139 :Uppskjuts fungerar inte i detta körläge +STR_3140 :Uppskjutsbacken måste börja direkt efter en station +STR_3141 :Kontinuerligt banläge går inte att kombinera med en uppskjutskulle +STR_3142 :{WINDOW_COLOUR_2}Kapacitet: {BLACK}{STRINGID} +STR_3143 :{SMALLFONT}{BLACK}Visa besökare på kartan +STR_3144 :{SMALLFONT}{BLACK}Visa åkturer och stånd på kartan +STR_3145 :{SMALLFONT}{BLACK}Flytta {STRINGID} vänster +STR_3146 :{SMALLFONT}{BLACK}Flytta {STRINGID} höger +STR_3147 :{SMALLFONT}{BLACK}Flytta {STRINGID} vänster snabbt +STR_3148 :{SMALLFONT}{BLACK}Flytta {STRINGID} höger snabbt +STR_3149 :{SMALLFONT}{BLACK}Flytta {STRINGID} vänster/höger +STR_3150 :{SMALLFONT}{BLACK}Flytta {STRINGID} upp +STR_3151 :{SMALLFONT}{BLACK}Flytta {STRINGID} ner +STR_3152 :{SMALLFONT}{BLACK}Flytta {STRINGID} upp snabbt +STR_3153 :{SMALLFONT}{BLACK}Flytta {STRINGID} ner snabbt +STR_3154 :{SMALLFONT}{BLACK}Flytta {STRINGID} upp/ner +STR_3155 : +STR_3156 : +STR_3157 :karta +STR_3158 :graf +STR_3159 :lista +STR_3160 :RollerCoaster Tycoon 2: Startar för första gången... +STR_3161 :RollerCoaster Tycoon 2: Kollar objektfiler... +STR_3162 :Kan inte allokera nog minne +STR_3163 :Installerar ny data: +STR_3164 :{BLACK}{COMMA16} valda (av max {COMMA16}) +STR_3165 : +STR_3166 :{BLACK}(ID: +STR_3167 :{WINDOW_COLOUR_2}Inkluderar: {BLACK}{COMMA16} objects +STR_3168 :{WINDOW_COLOUR_2}Text: {BLACK}{STRINGID} +STR_3169 :Data för detta objekt hittades ej: +STR_3170 :Inte nog plats för grafik +STR_3171 :För många objekt av denna typ är markerade +STR_3172 :Följande objekt måste markeras först: +STR_3173 :Detta objekt används just nu +STR_3174 :Detta objekt behövs av ett annat objekt +STR_3175 :Detta objekt behövs alltid +STR_3176 :Kan inte markera detta objekt +STR_3177 :Kan inte avmarkera detta objekt +STR_3178 :Minst ett gångvägsobjekt måste markeras +STR_3179 :Minst ett åktursfordon eller attraktionsobject måste markeras +STR_3180 :Ogiltig markering +STR_3181 :Objektmarkering - {STRINGID} +STR_3182 :Parkentrén måste markeras +STR_3183 :Vattentyp måste markeras +STR_3184 :Åktursfordon/attraktioner +STR_3185 :Små Dekorationer +STR_3186 :Stora Dekorationer +STR_3187 :Väggar/Staket +STR_3188 :Gångvägsskyltar +STR_3189 :Gångvägar +STR_3190 :Gångvägsdetaljer +STR_3191 :Dekorationsgrupper +STR_3192 :Parkentré +STR_3193 :Vatten +STR_3194 :Scenariobeskrivning +STR_3195 :Uppfinningslista +STR_3196 :{WINDOW_COLOUR_2}Forskningsgrupp: {BLACK}{STRINGID} +STR_3197 :{WINDOW_COLOUR_2}Saker som är inventerade vid spelets början: +STR_3198 :{WINDOW_COLOUR_2}Saker som ska inventeras under spelets gång: +STR_3199 :Slumpvis Ordning +STR_3200 :{SMALLFONT}{BLACK}Slumpa listan av saker som ska inventeras under spelets gång +STR_3201 :Välj Objekt +STR_3202 :Terrängeditor +STR_3203 :Bygg upp uppfinningslista +STR_3204 :Välj Inställningar +STR_3205 :Välj Uppdrag +STR_3206 :Spara Scenario +STR_3207 :Berg- och dalbane-designer +STR_3208 :Bandesignhanterare +STR_3209 :Tillbaka till tidigare steg: +STR_3210 :Vidare till nästa steg: +STR_3211 :{WINDOW_COLOUR_2}Kartstorlek: +STR_3212 :{POP16}{COMMA16} x {PUSH16}{COMMA16} +STR_3213 :Kan inte minska kartstorleken mer +STR_3214 :Kan inte utöka kartstorleken mer +STR_3215 :För nära kanten av kartan +STR_3216 :{SMALLFONT}{BLACK}Välj parkägd mark etc. +STR_3217 :Ägd Mark +STR_3218 :Bygglov innehas +STR_3219 :Mark Till Salu +STR_3220 :Bygglov Till Salu +STR_3221 :{SMALLFONT}{BLACK}Välj att marken ska ägas av parken +STR_3222 :{SMALLFONT}{BLACK}Välj att bara bygglov ska ägas av parken +STR_3223 :{SMALLFONT}{BLACK}Välj att mark ska vara tillgängligt för köp +STR_3224 :{SMALLFONT}{BLACK}Välj att bygglov ska vara tillgängligt för köp +STR_3225 :{SMALLFONT}{BLACK}Aktivera/inaktivera generering av en slumpmässig samling object runt den valda positionen +STR_3226 :{SMALLFONT}{BLACK}Bygg parkentré +STR_3227 :För många parkentréer! +STR_3228 :{SMALLFONT}{BLACK}Sätt startpositioner för besökare +STR_3229 :Blockbromsar kan inte användas direkt efter en station +STR_3230 :Blockbromsar kan inte användas direkt efter varandra +STR_3231 :Blockbromsar kan inte användas efter en uppskjutskulle +STR_3232 :Inställningar - Finansiella +STR_3233 :Inställningar - Gäster +STR_3234 :Inställningar - Parken +STR_3235 :{SMALLFONT}{BLACK}Visa finansiella inställningar +STR_3236 :{SMALLFONT}{BLACK}Visa gästinställningar +STR_3237 :{SMALLFONT}{BLACK}Visa parkinställningar +STR_3238 :Inga pengar +STR_3239 :{SMALLFONT}{BLACK}Gör detta till en 'inga pengar'-park utan finansiella begränsningar +STR_3240 :{WINDOW_COLOUR_2}Startpengar: +STR_3241 :{WINDOW_COLOUR_2}Startlån: +STR_3242 :{WINDOW_COLOUR_2}Maxlån: +STR_3243 :{WINDOW_COLOUR_2}Årlig ränta: +STR_3244 :Förbjud kampanjer +STR_3245 :{SMALLFONT}{BLACK}Förbjud kampanjer och marknadsföring +STR_3246 :{WINDOW_COLOUR_2}{CURRENCY} +STR_3247 :{WINDOW_COLOUR_2}{COMMA16}% +STR_3248 :Kan inte höja startpengar mer! +STR_3249 :Kan inte sänka startpengar mer! +STR_3250 :Kan inte höja startlån mer! +STR_3251 :Kan inte sänka startlån mer! +STR_3252 :Kan inte höja maxlån mer! +STR_3253 :Kan inte sänka maxlån mer! +STR_3254 :Kan inte höja räntan mer! +STR_3255 :Kan inte sänka räntan mer! +STR_3256 :Gäster föredrar mindre intensiva åkturer +STR_3257 :{SMALLFONT}{BLACK}Välj om gäster ska föredra mindre intensiva åkturer endast +STR_3258 :Gäster föredrar mer intensiva åkturer +STR_3259 :{SMALLFONT}{BLACK}Välj om gäster ska föredra mer intensiva åkturer endast +STR_3260 :{WINDOW_COLOUR_2}Pengar per gäst (genomsnitt): +STR_3261 :{WINDOW_COLOUR_2}Gästers startglädje: +STR_3262 :{WINDOW_COLOUR_2}Gästers starthunger: +STR_3263 :{WINDOW_COLOUR_2}Gästers starttörst: +STR_3264 :Kan inte höja detta mer! +STR_3265 :Kan inte sänka detta mer! +STR_3266 :{SMALLFONT}{BLACK}Välj hur den här parken tar betalt för entré och åkturer +STR_3267 :Förbjud borttagning av träd +STR_3268 :{SMALLFONT}{BLACK}Förbjud borttagning av höga träd +STR_3269 :Förbjud terrängändringar +STR_3270 :{SMALLFONT}{BLACK}Förbjud alla terrängändringar +STR_3271 :Förbjud höga konstruktioner +STR_3272 :{SMALLFONT}{BLACK}Förbjud alla höga konstruktioner +STR_3273 :Svårare parkomdöme +STR_3274 :{SMALLFONT}{BLACK}Gör så att bra parkomdöme är svårare att få +STR_3275 :Svårare gäster +STR_3276 :{SMALLFONT}{BLACK}Gör så att det blir svårare att få gäster +STR_3277 :{WINDOW_COLOUR_2}Kostnad för att köpa mark: +STR_3278 :{WINDOW_COLOUR_2}Kostnad för att köpa bygglov: +STR_3279 :Gratis parkentré / Betala per åktur +STR_3280 :Betala för parkentré / Gratis åkturer +STR_3281 :{WINDOW_COLOUR_2}Entrépris: +STR_3282 :{SMALLFONT}{BLACK}Välj uppdrag och parknamn +STR_3283 :{SMALLFONT}{BLACK}Välj åkturer som ska bevaras +STR_3284 :Uppdragsval +STR_3285 :Bevarade åkturer +STR_3286 :{SMALLFONT}{BLACK}Välj uppdrag för detta scenario +STR_3287 :{WINDOW_COLOUR_2}Uppdrag: +STR_3288 :{SMALLFONT}{BLACK}Välj klimat +STR_3289 :{WINDOW_COLOUR_2}Klimat: +STR_3290 :Svalt och blött +STR_3291 :Varmt +STR_3292 :Hett och torrt +STR_3293 :Kallt +STR_3294 :Byt... +STR_3295 :{SMALLFONT}{BLACK}Byt namn på parken +STR_3296 :{SMALLFONT}{BLACK}Byt namn på scenario +STR_3297 :{SMALLFONT}{BLACK}Byt detaljer om parken / scenariot +STR_3298 :{WINDOW_COLOUR_2}Parknamn: {BLACK}{STRINGID} +STR_3299 :{WINDOW_COLOUR_2}Park- och Scenariodetaljer: +STR_3300 :{WINDOW_COLOUR_2}Scenarionamn: {BLACK}{STRINGID} +STR_3301 :{WINDOW_COLOUR_2}Uppdragsdatum: +STR_3302 :{WINDOW_COLOUR_2}{MONTHYEAR} +STR_3303 :{WINDOW_COLOUR_2}Antal gäster: +STR_3304 :{WINDOW_COLOUR_2}Parkvärde: +STR_3305 :{WINDOW_COLOUR_2}Månadsinkomst: +STR_3306 :{WINDOW_COLOUR_2}Månadsvinst: +STR_3307 :{WINDOW_COLOUR_2}Minimilängd: +STR_3308 :{WINDOW_COLOUR_2}Glädjenivå: +STR_3309 :{WINDOW_COLOUR_2}{COMMA16} +STR_3310 :{WINDOW_COLOUR_2}{LENGTH} +STR_3311 :{WINDOW_COLOUR_2}{COMMA2DP32} +STR_3312 :{WINDOW_COLOUR_2}Åkturer/attraktioner som måste bevaras: +STR_3313 :Scenarionamn +STR_3314 :Skriv in namn för scenario:- +STR_3315 :Park- och Scenariodetails +STR_3316 :Skriv in en beskriving för detta scenario:- +STR_3317 :Inga detaljer än +STR_3318 :{SMALLFONT}{BLACK}Välj vilken grupp detta scenario hör till +STR_3319 :{WINDOW_COLOUR_2}Scenariogrupp: +STR_3320 :Kan inte spara scenariofil... +STR_3321 :Nya objekt installerade +STR_3322 :{WINDOW_COLOUR_2}Uppdrag: {BLACK}{STRINGID} +STR_3323 :Saknar objektdata, ID: +STR_3324 :Kräver Add-On Pack: +STR_3325 :Kräver ett Add-On Pack +STR_3326 :{WINDOW_COLOUR_2}(ingen bild) +STR_3327 :Startpositioner för besökare är inte bestämda +STR_3328 :Kan inte gå vidare till nästa steg... +STR_3329 :Parkentrén är inte byggd än +STR_3330 :Parken måste äga någon mark +STR_3331 :Vägen från parkentrén till kartkanten är antingen inte komplett eller för komplex - Vägen måste ha en konstant bredd med så få korsningar och hörn som möjligt +STR_3332 :Parkentrén är åt fel håll eller har ingen väg som leder till kartkanten +STR_3333 :Exportera plug-in-objekt med sparade spel +STR_3334 :{SMALLFONT}{BLACK}Välj om plug-in objekt (extra objekt som inte följer med basspelet) ska sparas i sparade spel och scenarion, vilket låter spelare importera denna data +STR_3335 :Berg- och dalbane-designer - Välj Åkturstyp & Fordon +STR_3336 :Bandesign-hanterare - Välj Åkturstype +STR_3337 :Six Flags Park +STR_3338 :{BLACK}Egendesignad layout +STR_3339 :{BLACK}{COMMA16} design tillgängliga, eller egendesignad layout +STR_3340 :{BLACK}{COMMA16} designer tillgängliga, eller egendesignad layout +STR_3341 :{SMALLFONT}{BLACK}Spelverktyg +STR_3342 :Scenario Editor +STR_3343 :Konvertera Sparat Spel till Scenario +STR_3344 :Berg- och dalbane-designer +STR_3345 :Bandesign-hanterare +STR_3346 :Kan inte spara bandesign... +STR_3347 :Åkturen är för stor, innehåller för många delar, eller så är dekorationerna för utspridda +STR_3348 :Döp om +STR_3349 :Ta bort +STR_3350 :Bandesignnamn +STR_3351 :Skriv in nytt namn på denna bandesign:- +STR_3352 :Kan inte namnge bandesign... +STR_3353 :Det nya namnet innehåller ogiltiga bokstäver eller symboler +STR_3354 :En annan fil finns redan med detta namn, eller så är filen skrivskyddad +STR_3355 :Filen är skrivskyddad eller låst +STR_3356 :Ta bort fil +STR_3357 :{WINDOW_COLOUR_2}Är du säker på att du permanent vill ta bort {STRINGID} ? +STR_3358 :Kan inte ta bort bandesign... +STR_3359 :{BLACK}Inga bandesigner av denna typ +STR_3360 :Varning! +STR_3361 :För många bandesigner av denna typ - Vissa kommer inte att visas. +STR_3362 :Tvingad Mjukvarubuffermixning +STR_3363 :{SMALLFONT}{BLACK}Välj detta för att förbättra prestanda om spelet pausas kort då ljud spelas eller om det blir interferens +STR_3364 :Avancerat +STR_3365 :{SMALLFONT}{BLACK}Tillåt urval av individuella dekorationer utöver dekorationsgrupper +STR_3366 :{BLACK}= Åktur +STR_3367 :{BLACK}= Matstånd +STR_3368 :{BLACK}= Drickstånd +STR_3369 :{BLACK}= Souvenirstånd +STR_3370 :{BLACK}= Infokiosk +STR_3371 :{BLACK}= Första Hjälpen +STR_3372 :{BLACK}= Bankomat +STR_3373 :{BLACK}= Toalett +STR_3374 :Varning: För många markerade objekt! +STR_3375 :Inte alla objekt i denna dekorationsgrupp kunde markeras +STR_3376 :Installera ny bandesign... +STR_3377 :{SMALLFONT}{BLACK}Installera en ny bandesignfil +STR_3378 :Installera +STR_3379 :Avbryt +STR_3380 :Kan inte installera denna bandesign... +STR_3381 :Filen är inte kompatibel eller så innehåller den ogiltig data +STR_3382 :Filkopiering misslyckades +STR_3383 :Välj nytt namn på denna bandesign +STR_3384 :En existerande bandesign har redan detta namn - Var god välj ett nytt namn för denna design: +STR_3385 :Handledning för Nybörjare +STR_3386 :Handledning för Egna åkturer +STR_3387 :Handledning för byggande av Berg- och dalbanor +STR_3388 :Kan inte byta till det valda läget +STR_3389 :Kan inte markera fler dekorationer... +STR_3390 :För många saker markerade +STR_3391 :{SMALLFONT}{BLACK}Här är vår park - Låt oss titta runt en snabbis... +STR_3392 :{SMALLFONT}{BLACK}Det snabbaste sättet att flytta kameran är att hålla ner den HÖGRA musknappen samtidigt som du flyttar musen... +STR_3393 :{SMALLFONT}{BLACK}För att se mer av parken kan du zooma ut genom att klicka på ikonen på toppen av skärmen... +STR_3394 :{SMALLFONT}{BLACK}Du kan också rotera vyn i 90-graders-steg... +STR_3395 :{SMALLFONT}{BLACK}Att bygga nånting i den här skalan är lite svårt, så vi zoomar in igen... +STR_3396 :{SMALLFONT}{BLACK}Låt oss bygga en enkel åktur för att komma igång med parken... +STR_3397 :{SMALLFONT}{BLACK}Den vita 'spökbilden' visar var åkturen kommer att byggas. Vi flyttar pekaren för att välja position, sen klickar vi för att bygga den... +STR_3398 :{SMALLFONT}{BLACK}Åkturer behöver en ingång och en utgång. Vi flyttar pekaren till en ruta på kanten av åkturen och sen klickar vi för att först bygga ingången och sen utgången... +STR_3399 :{SMALLFONT}{BLACK}Vi måste bygga gångvägar för att gästerna ska kunna komma fram till vår nya åktur... +STR_3400 :{SMALLFONT}{BLACK}För gångvägen till ingång ska vi använda en speciell 'kö'... +STR_3401 :{SMALLFONT}{BLACK}För utgången räcker det med en 'vanlig' gångväg... +STR_3402 :{SMALLFONT}{BLACK}Okej, nu öppnar vi åkturen! För att öppna åkturen klickar vi på flaggikonen på åktursfönstret och väljer 'Öppna'... +STR_3403 :{SMALLFONT}{BLACK}Men var är gästerna? +STR_3404 :{SMALLFONT}{BLACK}Åh - parken är fortfarande stängd! Okej - Vi öppnar den... +STR_3405 :{SMALLFONT}{BLACK}Medans vi väntar på våra första gäster kan vi bygga några dekorationer... +STR_3406 :{SMALLFONT}{BLACK}Här är vår tomma park. Vi ska bygga en enkel egendesignad åktur... +STR_3407 :{SMALLFONT}{BLACK}Först måste vi välja en startposition... +STR_3408 :{SMALLFONT}{BLACK}Den sektion av banan som vi byggde nyss är en 'stationsplatform', som låter gäster kliva på och av åkturen... +STR_3409 :{SMALLFONT}{BLACK}Vi utökar platformen lite grann genom att lägga till några till stationssektioner... +STR_3410 :{SMALLFONT}{BLACK}Ikonerna vid toppen av konstruktionsfönstret låter dig välja olika bansektioner som ska byggas... +STR_3411 :{SMALLFONT}{BLACK}Vi väljer en vänsterkurva... +STR_3412 :{SMALLFONT}{BLACK}Kurvan har inte blivit byggd än, men den vita spökbilden visar var den kommer byggas. Genom att klicka på den stora 'Bygg detta'-ikonen bygger du faktiskt banan... +STR_3413 :{SMALLFONT}{BLACK}Nu vill vi bygga rak bana, så vi klickar på rak bana-ikonen... +STR_3414 :{SMALLFONT}{BLACK}Nu när banan är komplett så behöver vi bygga ingången och utgången... +STR_3415 :{SMALLFONT}{BLACK}Dags att testa vår åktur för att se att den fungerar... +STR_3416 :{SMALLFONT}{BLACK}Medans den testas så bygger vi en kö och utgångsväg... +STR_3417 :{SMALLFONT}{BLACK}Okej - Låt oss öppna parken och åkturen... +STR_3418 :{SMALLFONT}{BLACK}Vår nya åktur är inte så spännande - Vi kanske borde lägga till några dekorationer? +STR_3419 :{SMALLFONT}{BLACK}För att bygga dekorationer ovanför andra dekorationer eller i luften, håll in SHIFT och flytta musen för att välja höjd... +STR_3420 :{SMALLFONT}{BLACK}Vissa sorts dekorationer kan målas om efter att de byggs... +STR_3421 :{SMALLFONT}{BLACK}Nu lägger vi till lite musik till åkturen... +STR_3422 :{SMALLFONT}{BLACK}Nu bygger vi en berg- och dalbana ! +STR_3423 :{SMALLFONT}{BLACK}Det finns massor av fördesignade berg- och dalbanor, men vi ska göra en egen design... +STR_3424 :{SMALLFONT}{BLACK}Nu har vi byggt stationsplatformen. Nu behöver vi en uppskjutsbacke... +STR_3425 :{SMALLFONT}{BLACK}Berg- och dalbane-tåg är inte motoriserade, så en lyftkedja behövs för att dra upp tåget för den första backen... +STR_3426 :{SMALLFONT}{BLACK}Då var uppskjutsbacken klar - Nu är det dags för vårt första fall... +STR_3427 :{SMALLFONT}{BLACK}Dom där kurvorna är en dålig idé - Passagerarna kommer att kastas åt sidan av laterala G-krafter när tåget flänger runt... +STR_3428 :{SMALLFONT}{BLACK}Sluttande kurvor kommer att förbättra åkturen - Passagerare kommer att tryckas ner i sina säten istället för att kastas åt sidan... +STR_3429 :{SMALLFONT}{BLACK}Nej - Det där kommer inte fungera! Kolla på höjdmarkeringarna - Den andra backen är högre än uppskjutskullen... +STR_3430 :{SMALLFONT}{BLACK}För att försäkra att tåget kommer runt så måste varje kulle vara lite längre än den innan... +STR_3431 :{SMALLFONT}{BLACK}Det där är bättre - Vårt tåg borde komma upp för backen nu! Dags att prova lite tvistad bana... +STR_3432 :{SMALLFONT}{BLACK}Vi måste sakta in tåget innan den sista kurvan och stationen, så vi lägger till några bromsar... +STR_3433 :{SMALLFONT}{BLACK}Till sist lägger vi till 'blockbromsar', som låter två tåg köras samtidigt mer säkert... +STR_3434 :{SMALLFONT}{BLACK}Nu testar vi åkturen och se om den fungerar! +STR_3435 :{SMALLFONT}{BLACK}Fantastiskt - Den fungerade! Dags att lägga till gångväger för att släppa in våra gäster till vår nya berg- och dalbana... +STR_3436 :{SMALLFONT}{BLACK}Medans vi väntar på våra första passagerare kan vi modifiera åkturen lite grann... +STR_3437 :{SMALLFONT}{BLACK}Rensa stora områden av dekorationer från terrängen +STR_3438 :Kan inte ta bort alla dekorationer härifrån... +STR_3439 :Rensa Dekorationer +STR_3440 :Sida 1 +STR_3441 :Sida 2 +STR_3442 :Sida 3 +STR_3443 :Sida 4 +STR_3444 :Sida 5 +STR_3445 :Sätt Patrullområde +STR_3446 :Avbryt Patrullområde diff --git a/install.sh b/install.sh index f4d69fb956..d9f7c93a95 100755 --- a/install.sh +++ b/install.sh @@ -51,7 +51,7 @@ if [[ `uname` == "Darwin" ]]; then mingw_name=mingw-w32-bin_i686-darwin mingw_tar=$mingw_name"_20130531".tar.bz2 - mingw_path=/usr/local/$mingw_name + mingw_path=/usr/local/$mingw_name/bin if [[ ! -f $cachedir/$mingw_tar ]]; then wget "https://downloads.sourceforge.net/project/mingw-w64/Toolchains targetting Win32/Automated Builds/$mingw_tar" --output-document $cachedir/$mingw_tar fi diff --git a/lib/libspeex/arch.h b/lib/libspeex/arch.h new file mode 100644 index 0000000000..d38c36ce7c --- /dev/null +++ b/lib/libspeex/arch.h @@ -0,0 +1,239 @@ +/* Copyright (C) 2003 Jean-Marc Valin */ +/** + @file arch.h + @brief Various architecture definitions Speex +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef ARCH_H +#define ARCH_H + +#ifndef SPEEX_VERSION +#define SPEEX_MAJOR_VERSION 1 /**< Major Speex version. */ +#define SPEEX_MINOR_VERSION 1 /**< Minor Speex version. */ +#define SPEEX_MICRO_VERSION 15 /**< Micro Speex version. */ +#define SPEEX_EXTRA_VERSION "" /**< Extra Speex version. */ +#define SPEEX_VERSION "speex-1.2beta3" /**< Speex version string. */ +#endif + +/* A couple test to catch stupid option combinations */ +#ifdef FIXED_POINT + +#ifdef FLOATING_POINT +#error You cannot compile as floating point and fixed point at the same time +#endif +#ifdef _USE_SSE +#error SSE is only for floating-point +#endif +#if ((defined (ARM4_ASM)||defined (ARM4_ASM)) && defined(BFIN_ASM)) || (defined (ARM4_ASM)&&defined(ARM5E_ASM)) +#error Make up your mind. What CPU do you have? +#endif +#ifdef VORBIS_PSYCHO +#error Vorbis-psy model currently not implemented in fixed-point +#endif + +#else + +#ifndef FLOATING_POINT +#error You now need to define either FIXED_POINT or FLOATING_POINT +#endif +#if defined (ARM4_ASM) || defined(ARM5E_ASM) || defined(BFIN_ASM) +#error I suppose you can have a [ARM4/ARM5E/Blackfin] that has float instructions? +#endif +#ifdef FIXED_POINT_DEBUG +#error "Don't you think enabling fixed-point is a good thing to do if you want to debug that?" +#endif + + +#endif + +#ifndef OUTSIDE_SPEEX +#include "speex/speex_types.h" +#endif + +#define ABS(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute integer value. */ +#define ABS16(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 16-bit value. */ +#define MIN16(a,b) ((a) < (b) ? (a) : (b)) /**< Maximum 16-bit value. */ +#define MAX16(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 16-bit value. */ +#define ABS32(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 32-bit value. */ +#define MIN32(a,b) ((a) < (b) ? (a) : (b)) /**< Maximum 32-bit value. */ +#define MAX32(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 32-bit value. */ + +#ifdef FIXED_POINT + +typedef spx_int16_t spx_word16_t; +typedef spx_int32_t spx_word32_t; +typedef spx_word32_t spx_mem_t; +typedef spx_word16_t spx_coef_t; +typedef spx_word16_t spx_lsp_t; +typedef spx_word32_t spx_sig_t; + +#define Q15ONE 32767 + +#define LPC_SCALING 8192 +#define SIG_SCALING 16384 +#define LSP_SCALING 8192. +#define GAMMA_SCALING 32768. +#define GAIN_SCALING 64 +#define GAIN_SCALING_1 0.015625 + +#define LPC_SHIFT 13 +#define LSP_SHIFT 13 +#define SIG_SHIFT 14 +#define GAIN_SHIFT 6 + +#define VERY_SMALL 0 +#define VERY_LARGE32 ((spx_word32_t)2147483647) +#define VERY_LARGE16 ((spx_word16_t)32767) +#define Q15_ONE ((spx_word16_t)32767) + + +#ifdef FIXED_DEBUG +#include "fixed_debug.h" +#else + +#include "fixed_generic.h" + +#ifdef ARM5E_ASM +#include "fixed_arm5e.h" +#elif defined (ARM4_ASM) +#include "fixed_arm4.h" +#elif defined (BFIN_ASM) +#include "fixed_bfin.h" +#endif + +#endif + + +#else + +typedef float spx_mem_t; +typedef float spx_coef_t; +typedef float spx_lsp_t; +typedef float spx_sig_t; +typedef float spx_word16_t; +typedef float spx_word32_t; + +#define Q15ONE 1.0f +#define LPC_SCALING 1.f +#define SIG_SCALING 1.f +#define LSP_SCALING 1.f +#define GAMMA_SCALING 1.f +#define GAIN_SCALING 1.f +#define GAIN_SCALING_1 1.f + + +#define VERY_SMALL 1e-15f +#define VERY_LARGE32 1e15f +#define VERY_LARGE16 1e15f +#define Q15_ONE ((spx_word16_t)1.f) + +#define QCONST16(x,bits) (x) +#define QCONST32(x,bits) (x) + +#define NEG16(x) (-(x)) +#define NEG32(x) (-(x)) +#define EXTRACT16(x) (x) +#define EXTEND32(x) (x) +#define SHR16(a,shift) (a) +#define SHL16(a,shift) (a) +#define SHR32(a,shift) (a) +#define SHL32(a,shift) (a) +#define PSHR16(a,shift) (a) +#define PSHR32(a,shift) (a) +#define VSHR32(a,shift) (a) +#define SATURATE16(x,a) (x) +#define SATURATE32(x,a) (x) + +#define PSHR(a,shift) (a) +#define SHR(a,shift) (a) +#define SHL(a,shift) (a) +#define SATURATE(x,a) (x) + +#define ADD16(a,b) ((a)+(b)) +#define SUB16(a,b) ((a)-(b)) +#define ADD32(a,b) ((a)+(b)) +#define SUB32(a,b) ((a)-(b)) +#define MULT16_16_16(a,b) ((a)*(b)) +#define MULT16_16(a,b) ((spx_word32_t)(a)*(spx_word32_t)(b)) +#define MAC16_16(c,a,b) ((c)+(spx_word32_t)(a)*(spx_word32_t)(b)) + +#define MULT16_32_Q11(a,b) ((a)*(b)) +#define MULT16_32_Q13(a,b) ((a)*(b)) +#define MULT16_32_Q14(a,b) ((a)*(b)) +#define MULT16_32_Q15(a,b) ((a)*(b)) +#define MULT16_32_P15(a,b) ((a)*(b)) + +#define MAC16_32_Q11(c,a,b) ((c)+(a)*(b)) +#define MAC16_32_Q15(c,a,b) ((c)+(a)*(b)) + +#define MAC16_16_Q11(c,a,b) ((c)+(a)*(b)) +#define MAC16_16_Q13(c,a,b) ((c)+(a)*(b)) +#define MAC16_16_P13(c,a,b) ((c)+(a)*(b)) +#define MULT16_16_Q11_32(a,b) ((a)*(b)) +#define MULT16_16_Q13(a,b) ((a)*(b)) +#define MULT16_16_Q14(a,b) ((a)*(b)) +#define MULT16_16_Q15(a,b) ((a)*(b)) +#define MULT16_16_P15(a,b) ((a)*(b)) +#define MULT16_16_P13(a,b) ((a)*(b)) +#define MULT16_16_P14(a,b) ((a)*(b)) + +#define DIV32_16(a,b) (((spx_word32_t)(a))/(spx_word16_t)(b)) +#define PDIV32_16(a,b) (((spx_word32_t)(a))/(spx_word16_t)(b)) +#define DIV32(a,b) (((spx_word32_t)(a))/(spx_word32_t)(b)) +#define PDIV32(a,b) (((spx_word32_t)(a))/(spx_word32_t)(b)) + + +#endif + + +#if defined (CONFIG_TI_C54X) || defined (CONFIG_TI_C55X) + +/* 2 on TI C5x DSP */ +#define BYTES_PER_CHAR 2 +#define BITS_PER_CHAR 16 +#define LOG2_BITS_PER_CHAR 4 + +#else + +#define BYTES_PER_CHAR 1 +#define BITS_PER_CHAR 8 +#define LOG2_BITS_PER_CHAR 3 + +#endif + + + +#ifdef FIXED_DEBUG +extern long long spx_mips; +#endif + + +#endif diff --git a/lib/libspeex/config.h b/lib/libspeex/config.h new file mode 100644 index 0000000000..abd35f0914 --- /dev/null +++ b/lib/libspeex/config.h @@ -0,0 +1,20 @@ +// Microsoft version of 'inline' +#define inline __inline + +// Visual Studio support alloca(), but it always align variables to 16-bit +// boundary, while SSE need 128-bit alignment. So we disable alloca() when +// SSE is enabled. +#ifndef _USE_SSE +# define USE_ALLOCA +#endif + +/* Default to floating point */ +#ifndef FIXED_POINT +# define FLOATING_POINT +# define USE_SMALLFT +#else +# define USE_KISS_FFT +#endif + +/* We don't support visibility on Win32 */ +#define EXPORT diff --git a/lib/libspeex/os_support.h b/lib/libspeex/os_support.h new file mode 100644 index 0000000000..6b74b0c22f --- /dev/null +++ b/lib/libspeex/os_support.h @@ -0,0 +1,169 @@ +/* Copyright (C) 2007 Jean-Marc Valin + + File: os_support.h + This is the (tiny) OS abstraction layer. Aside from math.h, this is the + only place where system headers are allowed. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef OS_SUPPORT_H +#define OS_SUPPORT_H + +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef OS_SUPPORT_CUSTOM +#include "os_support_custom.h" +#endif + +/** Speex wrapper for calloc. To do your own dynamic allocation, all you need to do is replace this function, speex_realloc and speex_free + NOTE: speex_alloc needs to CLEAR THE MEMORY */ +#ifndef OVERRIDE_SPEEX_ALLOC +static inline void *speex_alloc (int size) +{ + /* WARNING: this is not equivalent to malloc(). If you want to use malloc() + or your own allocator, YOU NEED TO CLEAR THE MEMORY ALLOCATED. Otherwise + you will experience strange bugs */ + return calloc(size,1); +} +#endif + +/** Same as speex_alloc, except that the area is only needed inside a Speex call (might cause problem with wideband though) */ +#ifndef OVERRIDE_SPEEX_ALLOC_SCRATCH +static inline void *speex_alloc_scratch (int size) +{ + /* Scratch space doesn't need to be cleared */ + return calloc(size,1); +} +#endif + +/** Speex wrapper for realloc. To do your own dynamic allocation, all you need to do is replace this function, speex_alloc and speex_free */ +#ifndef OVERRIDE_SPEEX_REALLOC +static inline void *speex_realloc (void *ptr, int size) +{ + return realloc(ptr, size); +} +#endif + +/** Speex wrapper for calloc. To do your own dynamic allocation, all you need to do is replace this function, speex_realloc and speex_alloc */ +#ifndef OVERRIDE_SPEEX_FREE +static inline void speex_free (void *ptr) +{ + free(ptr); +} +#endif + +/** Same as speex_free, except that the area is only needed inside a Speex call (might cause problem with wideband though) */ +#ifndef OVERRIDE_SPEEX_FREE_SCRATCH +static inline void speex_free_scratch (void *ptr) +{ + free(ptr); +} +#endif + +/** Copy n bytes of memory from src to dst. The 0* term provides compile-time type checking */ +#ifndef OVERRIDE_SPEEX_COPY +#define SPEEX_COPY(dst, src, n) (memcpy((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) )) +#endif + +/** Copy n bytes of memory from src to dst, allowing overlapping regions. The 0* term + provides compile-time type checking */ +#ifndef OVERRIDE_SPEEX_MOVE +#define SPEEX_MOVE(dst, src, n) (memmove((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) )) +#endif + +/** Set n bytes of memory to value of c, starting at address s */ +#ifndef OVERRIDE_SPEEX_MEMSET +#define SPEEX_MEMSET(dst, c, n) (memset((dst), (c), (n)*sizeof(*(dst)))) +#endif + + +#ifndef OVERRIDE_SPEEX_FATAL +static inline void _speex_fatal(const char *str, const char *file, int line) +{ + fprintf (stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str); + exit(1); +} +#endif + +#ifndef OVERRIDE_SPEEX_WARNING +static inline void speex_warning(const char *str) +{ +#ifndef DISABLE_WARNINGS + fprintf (stderr, "warning: %s\n", str); +#endif +} +#endif + +#ifndef OVERRIDE_SPEEX_WARNING_INT +static inline void speex_warning_int(const char *str, int val) +{ +#ifndef DISABLE_WARNINGS + fprintf (stderr, "warning: %s %d\n", str, val); +#endif +} +#endif + +#ifndef OVERRIDE_SPEEX_NOTIFY +static inline void speex_notify(const char *str) +{ +#ifndef DISABLE_NOTIFICATIONS + fprintf (stderr, "notification: %s\n", str); +#endif +} +#endif + +#ifndef OVERRIDE_SPEEX_PUTC +/** Speex wrapper for putc */ +static inline void _speex_putc(int ch, void *file) +{ + FILE *f = (FILE *)file; + fprintf(f, "%c", ch); +} +#endif + +#define speex_fatal(str) _speex_fatal(str, __FILE__, __LINE__); +#define speex_assert(cond) {if (!(cond)) {speex_fatal("assertion failed: " #cond);}} + +#ifndef RELEASE +static inline void print_vec(float *vec, int len, char *name) +{ + int i; + printf ("%s ", name); + for (i=0;i +static void *speex_alloc (int size) {return calloc(size,1);} +static void *speex_realloc (void *ptr, int size) {return realloc(ptr, size);} +static void speex_free (void *ptr) {free(ptr);} +#include "speex_resampler.h" +#include "arch.h" +#else /* OUTSIDE_SPEEX */ + +#include "speex/speex_resampler.h" +#include "arch.h" +#include "os_support.h" +#endif /* OUTSIDE_SPEEX */ + +#include "stack_alloc.h" +#include + +#ifndef M_PI +#define M_PI 3.14159263 +#endif + +#ifdef FIXED_POINT +#define WORD2INT(x) ((x) < -32767 ? -32768 : ((x) > 32766 ? 32767 : (x))) +#else +#define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x)))) +#endif + +#define IMAX(a,b) ((a) > (b) ? (a) : (b)) +#define IMIN(a,b) ((a) < (b) ? (a) : (b)) + +#ifndef NULL +#define NULL 0 +#endif + +#ifdef _USE_SSE +#include "resample_sse.h" +#endif + +/* Numer of elements to allocate on the stack */ +#ifdef VAR_ARRAYS +#define FIXED_STACK_ALLOC 8192 +#else +#define FIXED_STACK_ALLOC 1024 +#endif + +typedef int (*resampler_basic_func)(SpeexResamplerState *, spx_uint32_t , const spx_word16_t *, spx_uint32_t *, spx_word16_t *, spx_uint32_t *); + +struct SpeexResamplerState_ { + spx_uint32_t in_rate; + spx_uint32_t out_rate; + spx_uint32_t num_rate; + spx_uint32_t den_rate; + + int quality; + spx_uint32_t nb_channels; + spx_uint32_t filt_len; + spx_uint32_t mem_alloc_size; + spx_uint32_t buffer_size; + int int_advance; + int frac_advance; + float cutoff; + spx_uint32_t oversample; + int initialised; + int started; + + /* These are per-channel */ + spx_int32_t *last_sample; + spx_uint32_t *samp_frac_num; + spx_uint32_t *magic_samples; + + spx_word16_t *mem; + spx_word16_t *sinc_table; + spx_uint32_t sinc_table_length; + resampler_basic_func resampler_ptr; + + int in_stride; + int out_stride; +} ; + +static double kaiser12_table[68] = { + 0.99859849, 1.00000000, 0.99859849, 0.99440475, 0.98745105, 0.97779076, + 0.96549770, 0.95066529, 0.93340547, 0.91384741, 0.89213598, 0.86843014, + 0.84290116, 0.81573067, 0.78710866, 0.75723148, 0.72629970, 0.69451601, + 0.66208321, 0.62920216, 0.59606986, 0.56287762, 0.52980938, 0.49704014, + 0.46473455, 0.43304576, 0.40211431, 0.37206735, 0.34301800, 0.31506490, + 0.28829195, 0.26276832, 0.23854851, 0.21567274, 0.19416736, 0.17404546, + 0.15530766, 0.13794294, 0.12192957, 0.10723616, 0.09382272, 0.08164178, + 0.07063950, 0.06075685, 0.05193064, 0.04409466, 0.03718069, 0.03111947, + 0.02584161, 0.02127838, 0.01736250, 0.01402878, 0.01121463, 0.00886058, + 0.00691064, 0.00531256, 0.00401805, 0.00298291, 0.00216702, 0.00153438, + 0.00105297, 0.00069463, 0.00043489, 0.00025272, 0.00013031, 0.0000527734, + 0.00001000, 0.00000000}; +/* +static double kaiser12_table[36] = { + 0.99440475, 1.00000000, 0.99440475, 0.97779076, 0.95066529, 0.91384741, + 0.86843014, 0.81573067, 0.75723148, 0.69451601, 0.62920216, 0.56287762, + 0.49704014, 0.43304576, 0.37206735, 0.31506490, 0.26276832, 0.21567274, + 0.17404546, 0.13794294, 0.10723616, 0.08164178, 0.06075685, 0.04409466, + 0.03111947, 0.02127838, 0.01402878, 0.00886058, 0.00531256, 0.00298291, + 0.00153438, 0.00069463, 0.00025272, 0.0000527734, 0.00000500, 0.00000000}; +*/ +static double kaiser10_table[36] = { + 0.99537781, 1.00000000, 0.99537781, 0.98162644, 0.95908712, 0.92831446, + 0.89005583, 0.84522401, 0.79486424, 0.74011713, 0.68217934, 0.62226347, + 0.56155915, 0.50119680, 0.44221549, 0.38553619, 0.33194107, 0.28205962, + 0.23636152, 0.19515633, 0.15859932, 0.12670280, 0.09935205, 0.07632451, + 0.05731132, 0.04193980, 0.02979584, 0.02044510, 0.01345224, 0.00839739, + 0.00488951, 0.00257636, 0.00115101, 0.00035515, 0.00000000, 0.00000000}; + +static double kaiser8_table[36] = { + 0.99635258, 1.00000000, 0.99635258, 0.98548012, 0.96759014, 0.94302200, + 0.91223751, 0.87580811, 0.83439927, 0.78875245, 0.73966538, 0.68797126, + 0.63451750, 0.58014482, 0.52566725, 0.47185369, 0.41941150, 0.36897272, + 0.32108304, 0.27619388, 0.23465776, 0.19672670, 0.16255380, 0.13219758, + 0.10562887, 0.08273982, 0.06335451, 0.04724088, 0.03412321, 0.02369490, + 0.01563093, 0.00959968, 0.00527363, 0.00233883, 0.00050000, 0.00000000}; + +static double kaiser6_table[36] = { + 0.99733006, 1.00000000, 0.99733006, 0.98935595, 0.97618418, 0.95799003, + 0.93501423, 0.90755855, 0.87598009, 0.84068475, 0.80211977, 0.76076565, + 0.71712752, 0.67172623, 0.62508937, 0.57774224, 0.53019925, 0.48295561, + 0.43647969, 0.39120616, 0.34752997, 0.30580127, 0.26632152, 0.22934058, + 0.19505503, 0.16360756, 0.13508755, 0.10953262, 0.08693120, 0.06722600, + 0.05031820, 0.03607231, 0.02432151, 0.01487334, 0.00752000, 0.00000000}; + +struct FuncDef { + double *table; + int oversample; +}; + +static struct FuncDef _KAISER12 = {kaiser12_table, 64}; +#define KAISER12 (&_KAISER12) +/*static struct FuncDef _KAISER12 = {kaiser12_table, 32}; +#define KAISER12 (&_KAISER12)*/ +static struct FuncDef _KAISER10 = {kaiser10_table, 32}; +#define KAISER10 (&_KAISER10) +static struct FuncDef _KAISER8 = {kaiser8_table, 32}; +#define KAISER8 (&_KAISER8) +static struct FuncDef _KAISER6 = {kaiser6_table, 32}; +#define KAISER6 (&_KAISER6) + +struct QualityMapping { + int base_length; + int oversample; + float downsample_bandwidth; + float upsample_bandwidth; + struct FuncDef *window_func; +}; + + +/* This table maps conversion quality to internal parameters. There are two + reasons that explain why the up-sampling bandwidth is larger than the + down-sampling bandwidth: + 1) When up-sampling, we can assume that the spectrum is already attenuated + close to the Nyquist rate (from an A/D or a previous resampling filter) + 2) Any aliasing that occurs very close to the Nyquist rate will be masked + by the sinusoids/noise just below the Nyquist rate (guaranteed only for + up-sampling). +*/ +static const struct QualityMapping quality_map[11] = { + { 8, 4, 0.830f, 0.860f, KAISER6 }, /* Q0 */ + { 16, 4, 0.850f, 0.880f, KAISER6 }, /* Q1 */ + { 32, 4, 0.882f, 0.910f, KAISER6 }, /* Q2 */ /* 82.3% cutoff ( ~60 dB stop) 6 */ + { 48, 8, 0.895f, 0.917f, KAISER8 }, /* Q3 */ /* 84.9% cutoff ( ~80 dB stop) 8 */ + { 64, 8, 0.921f, 0.940f, KAISER8 }, /* Q4 */ /* 88.7% cutoff ( ~80 dB stop) 8 */ + { 80, 16, 0.922f, 0.940f, KAISER10}, /* Q5 */ /* 89.1% cutoff (~100 dB stop) 10 */ + { 96, 16, 0.940f, 0.945f, KAISER10}, /* Q6 */ /* 91.5% cutoff (~100 dB stop) 10 */ + {128, 16, 0.950f, 0.950f, KAISER10}, /* Q7 */ /* 93.1% cutoff (~100 dB stop) 10 */ + {160, 16, 0.960f, 0.960f, KAISER10}, /* Q8 */ /* 94.5% cutoff (~100 dB stop) 10 */ + {192, 32, 0.968f, 0.968f, KAISER12}, /* Q9 */ /* 95.5% cutoff (~100 dB stop) 10 */ + {256, 32, 0.975f, 0.975f, KAISER12}, /* Q10 */ /* 96.6% cutoff (~100 dB stop) 10 */ +}; +/*8,24,40,56,80,104,128,160,200,256,320*/ +static double compute_func(float x, struct FuncDef *func) +{ + float y, frac; + double interp[4]; + int ind; + y = x*func->oversample; + ind = (int)floor(y); + frac = (y-ind); + /* CSE with handle the repeated powers */ + interp[3] = -0.1666666667*frac + 0.1666666667*(frac*frac*frac); + interp[2] = frac + 0.5*(frac*frac) - 0.5*(frac*frac*frac); + /*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/ + interp[0] = -0.3333333333*frac + 0.5*(frac*frac) - 0.1666666667*(frac*frac*frac); + /* Just to make sure we don't have rounding problems */ + interp[1] = 1.f-interp[3]-interp[2]-interp[0]; + + /*sum = frac*accum[1] + (1-frac)*accum[2];*/ + return interp[0]*func->table[ind] + interp[1]*func->table[ind+1] + interp[2]*func->table[ind+2] + interp[3]*func->table[ind+3]; +} + +#if 0 +#include +int main(int argc, char **argv) +{ + int i; + for (i=0;i<256;i++) + { + printf ("%f\n", compute_func(i/256., KAISER12)); + } + return 0; +} +#endif + +#ifdef FIXED_POINT +/* The slow way of computing a sinc for the table. Should improve that some day */ +static spx_word16_t sinc(float cutoff, float x, int N, struct FuncDef *window_func) +{ + /*fprintf (stderr, "%f ", x);*/ + float xx = x * cutoff; + if (fabs(x)<1e-6f) + return WORD2INT(32768.*cutoff); + else if (fabs(x) > .5f*N) + return 0; + /*FIXME: Can it really be any slower than this? */ + return WORD2INT(32768.*cutoff*sin(M_PI*xx)/(M_PI*xx) * compute_func(fabs(2.*x/N), window_func)); +} +#else +/* The slow way of computing a sinc for the table. Should improve that some day */ +static spx_word16_t sinc(float cutoff, float x, int N, struct FuncDef *window_func) +{ + /*fprintf (stderr, "%f ", x);*/ + float xx = x * cutoff; + if (fabs(x)<1e-6) + return cutoff; + else if (fabs(x) > .5*N) + return 0; + /*FIXME: Can it really be any slower than this? */ + return cutoff*sin(M_PI*xx)/(M_PI*xx) * compute_func(fabs(2.*x/N), window_func); +} +#endif + +#ifdef FIXED_POINT +static void cubic_coef(spx_word16_t x, spx_word16_t interp[4]) +{ + /* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation + but I know it's MMSE-optimal on a sinc */ + spx_word16_t x2, x3; + x2 = MULT16_16_P15(x, x); + x3 = MULT16_16_P15(x, x2); + interp[0] = PSHR32(MULT16_16(QCONST16(-0.16667f, 15),x) + MULT16_16(QCONST16(0.16667f, 15),x3),15); + interp[1] = EXTRACT16(EXTEND32(x) + SHR32(SUB32(EXTEND32(x2),EXTEND32(x3)),1)); + interp[3] = PSHR32(MULT16_16(QCONST16(-0.33333f, 15),x) + MULT16_16(QCONST16(.5f,15),x2) - MULT16_16(QCONST16(0.16667f, 15),x3),15); + /* Just to make sure we don't have rounding problems */ + interp[2] = Q15_ONE-interp[0]-interp[1]-interp[3]; + if (interp[2]<32767) + interp[2]+=1; +} +#else +static void cubic_coef(spx_word16_t frac, spx_word16_t interp[4]) +{ + /* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation + but I know it's MMSE-optimal on a sinc */ + interp[0] = -0.16667f*frac + 0.16667f*frac*frac*frac; + interp[1] = frac + 0.5f*frac*frac - 0.5f*frac*frac*frac; + /*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/ + interp[3] = -0.33333f*frac + 0.5f*frac*frac - 0.16667f*frac*frac*frac; + /* Just to make sure we don't have rounding problems */ + interp[2] = 1.-interp[0]-interp[1]-interp[3]; +} +#endif + +static int resampler_basic_direct_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) +{ + const int N = st->filt_len; + int out_sample = 0; + int last_sample = st->last_sample[channel_index]; + spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; + const spx_word16_t *sinc_table = st->sinc_table; + const int out_stride = st->out_stride; + const int int_advance = st->int_advance; + const int frac_advance = st->frac_advance; + const spx_uint32_t den_rate = st->den_rate; + spx_word32_t sum; + int j; + + while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) + { + const spx_word16_t *sinc = & sinc_table[samp_frac_num*N]; + const spx_word16_t *iptr = & in[last_sample]; + +#ifndef OVERRIDE_INNER_PRODUCT_SINGLE + float accum[4] = {0,0,0,0}; + + for(j=0;j= den_rate) + { + samp_frac_num -= den_rate; + last_sample++; + } + } + + st->last_sample[channel_index] = last_sample; + st->samp_frac_num[channel_index] = samp_frac_num; + return out_sample; +} + +#ifdef FIXED_POINT +#else +/* This is the same as the previous function, except with a double-precision accumulator */ +static int resampler_basic_direct_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) +{ + const int N = st->filt_len; + int out_sample = 0; + int last_sample = st->last_sample[channel_index]; + spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; + const spx_word16_t *sinc_table = st->sinc_table; + const int out_stride = st->out_stride; + const int int_advance = st->int_advance; + const int frac_advance = st->frac_advance; + const spx_uint32_t den_rate = st->den_rate; + double sum; + int j; + + while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) + { + const spx_word16_t *sinc = & sinc_table[samp_frac_num*N]; + const spx_word16_t *iptr = & in[last_sample]; + +#ifndef OVERRIDE_INNER_PRODUCT_DOUBLE + double accum[4] = {0,0,0,0}; + + for(j=0;j= den_rate) + { + samp_frac_num -= den_rate; + last_sample++; + } + } + + st->last_sample[channel_index] = last_sample; + st->samp_frac_num[channel_index] = samp_frac_num; + return out_sample; +} +#endif + +static int resampler_basic_interpolate_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) +{ + const int N = st->filt_len; + int out_sample = 0; + int last_sample = st->last_sample[channel_index]; + spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; + const int out_stride = st->out_stride; + const int int_advance = st->int_advance; + const int frac_advance = st->frac_advance; + const spx_uint32_t den_rate = st->den_rate; + int j; + spx_word32_t sum; + + while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) + { + const spx_word16_t *iptr = & in[last_sample]; + + const int offset = samp_frac_num*st->oversample/st->den_rate; +#ifdef FIXED_POINT + const spx_word16_t frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate); +#else + const spx_word16_t frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate; +#endif + spx_word16_t interp[4]; + + +#ifndef OVERRIDE_INTERPOLATE_PRODUCT_SINGLE + spx_word32_t accum[4] = {0,0,0,0}; + + for(j=0;jsinc_table[4+(j+1)*st->oversample-offset-2]); + accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]); + accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]); + accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]); + } + + cubic_coef(frac, interp); + sum = MULT16_32_Q15(interp[0],accum[0]) + MULT16_32_Q15(interp[1],accum[1]) + MULT16_32_Q15(interp[2],accum[2]) + MULT16_32_Q15(interp[3],accum[3]); +#else + cubic_coef(frac, interp); + sum = interpolate_product_single(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp); +#endif + + out[out_stride * out_sample++] = PSHR32(sum,15); + last_sample += int_advance; + samp_frac_num += frac_advance; + if (samp_frac_num >= den_rate) + { + samp_frac_num -= den_rate; + last_sample++; + } + } + + st->last_sample[channel_index] = last_sample; + st->samp_frac_num[channel_index] = samp_frac_num; + return out_sample; +} + +#ifdef FIXED_POINT +#else +/* This is the same as the previous function, except with a double-precision accumulator */ +static int resampler_basic_interpolate_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) +{ + const int N = st->filt_len; + int out_sample = 0; + int last_sample = st->last_sample[channel_index]; + spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; + const int out_stride = st->out_stride; + const int int_advance = st->int_advance; + const int frac_advance = st->frac_advance; + const spx_uint32_t den_rate = st->den_rate; + int j; + spx_word32_t sum; + + while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) + { + const spx_word16_t *iptr = & in[last_sample]; + + const int offset = samp_frac_num*st->oversample/st->den_rate; +#ifdef FIXED_POINT + const spx_word16_t frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate); +#else + const spx_word16_t frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate; +#endif + spx_word16_t interp[4]; + + +#ifndef OVERRIDE_INTERPOLATE_PRODUCT_DOUBLE + double accum[4] = {0,0,0,0}; + + for(j=0;jsinc_table[4+(j+1)*st->oversample-offset-2]); + accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]); + accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]); + accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]); + } + + cubic_coef(frac, interp); + sum = MULT16_32_Q15(interp[0],accum[0]) + MULT16_32_Q15(interp[1],accum[1]) + MULT16_32_Q15(interp[2],accum[2]) + MULT16_32_Q15(interp[3],accum[3]); +#else + cubic_coef(frac, interp); + sum = interpolate_product_double(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp); +#endif + + out[out_stride * out_sample++] = PSHR32(sum,15); + last_sample += int_advance; + samp_frac_num += frac_advance; + if (samp_frac_num >= den_rate) + { + samp_frac_num -= den_rate; + last_sample++; + } + } + + st->last_sample[channel_index] = last_sample; + st->samp_frac_num[channel_index] = samp_frac_num; + return out_sample; +} +#endif + +static void update_filter(SpeexResamplerState *st) +{ + spx_uint32_t old_length; + + old_length = st->filt_len; + st->oversample = quality_map[st->quality].oversample; + st->filt_len = quality_map[st->quality].base_length; + + if (st->num_rate > st->den_rate) + { + /* down-sampling */ + st->cutoff = quality_map[st->quality].downsample_bandwidth * st->den_rate / st->num_rate; + /* FIXME: divide the numerator and denominator by a certain amount if they're too large */ + st->filt_len = st->filt_len*st->num_rate / st->den_rate; + /* Round down to make sure we have a multiple of 4 */ + st->filt_len &= (~0x3); + if (2*st->den_rate < st->num_rate) + st->oversample >>= 1; + if (4*st->den_rate < st->num_rate) + st->oversample >>= 1; + if (8*st->den_rate < st->num_rate) + st->oversample >>= 1; + if (16*st->den_rate < st->num_rate) + st->oversample >>= 1; + if (st->oversample < 1) + st->oversample = 1; + } else { + /* up-sampling */ + st->cutoff = quality_map[st->quality].upsample_bandwidth; + } + + /* Choose the resampling type that requires the least amount of memory */ + if (st->den_rate <= st->oversample) + { + spx_uint32_t i; + if (!st->sinc_table) + st->sinc_table = (spx_word16_t *)speex_alloc(st->filt_len*st->den_rate*sizeof(spx_word16_t)); + else if (st->sinc_table_length < st->filt_len*st->den_rate) + { + st->sinc_table = (spx_word16_t *)speex_realloc(st->sinc_table,st->filt_len*st->den_rate*sizeof(spx_word16_t)); + st->sinc_table_length = st->filt_len*st->den_rate; + } + for (i=0;iden_rate;i++) + { + spx_int32_t j; + for (j=0;jfilt_len;j++) + { + st->sinc_table[i*st->filt_len+j] = sinc(st->cutoff,((j-(spx_int32_t)st->filt_len/2+1)-((float)i)/st->den_rate), st->filt_len, quality_map[st->quality].window_func); + } + } +#ifdef FIXED_POINT + st->resampler_ptr = resampler_basic_direct_single; +#else + if (st->quality>8) + st->resampler_ptr = resampler_basic_direct_double; + else + st->resampler_ptr = resampler_basic_direct_single; +#endif + /*fprintf (stderr, "resampler uses direct sinc table and normalised cutoff %f\n", cutoff);*/ + } else { + spx_int32_t i; + if (!st->sinc_table) + st->sinc_table = (spx_word16_t *)speex_alloc((st->filt_len*st->oversample+8)*sizeof(spx_word16_t)); + else if (st->sinc_table_length < st->filt_len*st->oversample+8) + { + st->sinc_table = (spx_word16_t *)speex_realloc(st->sinc_table,(st->filt_len*st->oversample+8)*sizeof(spx_word16_t)); + st->sinc_table_length = st->filt_len*st->oversample+8; + } + for (i=-4;i<(spx_int32_t)(st->oversample*st->filt_len+4);i++) + st->sinc_table[i+4] = sinc(st->cutoff,(i/(float)st->oversample - st->filt_len/2), st->filt_len, quality_map[st->quality].window_func); +#ifdef FIXED_POINT + st->resampler_ptr = resampler_basic_interpolate_single; +#else + if (st->quality>8) + st->resampler_ptr = resampler_basic_interpolate_double; + else + st->resampler_ptr = resampler_basic_interpolate_single; +#endif + /*fprintf (stderr, "resampler uses interpolated sinc table and normalised cutoff %f\n", cutoff);*/ + } + st->int_advance = st->num_rate/st->den_rate; + st->frac_advance = st->num_rate%st->den_rate; + + + /* Here's the place where we update the filter memory to take into account + the change in filter length. It's probably the messiest part of the code + due to handling of lots of corner cases. */ + if (!st->mem) + { + spx_uint32_t i; + st->mem_alloc_size = st->filt_len-1 + st->buffer_size; + st->mem = (spx_word16_t*)speex_alloc(st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t)); + for (i=0;inb_channels*st->mem_alloc_size;i++) + st->mem[i] = 0; + /*speex_warning("init filter");*/ + } else if (!st->started) + { + spx_uint32_t i; + st->mem_alloc_size = st->filt_len-1 + st->buffer_size; + st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t)); + for (i=0;inb_channels*st->mem_alloc_size;i++) + st->mem[i] = 0; + /*speex_warning("reinit filter");*/ + } else if (st->filt_len > old_length) + { + spx_int32_t i; + /* Increase the filter length */ + /*speex_warning("increase filter size");*/ + int old_alloc_size = st->mem_alloc_size; + if ((st->filt_len-1 + st->buffer_size) > st->mem_alloc_size) + { + st->mem_alloc_size = st->filt_len-1 + st->buffer_size; + st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t)); + } + for (i=st->nb_channels-1;i>=0;i--) + { + spx_int32_t j; + spx_uint32_t olen = old_length; + /*if (st->magic_samples[i])*/ + { + /* Try and remove the magic samples as if nothing had happened */ + + /* FIXME: This is wrong but for now we need it to avoid going over the array bounds */ + olen = old_length + 2*st->magic_samples[i]; + for (j=old_length-2+st->magic_samples[i];j>=0;j--) + st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]] = st->mem[i*old_alloc_size+j]; + for (j=0;jmagic_samples[i];j++) + st->mem[i*st->mem_alloc_size+j] = 0; + st->magic_samples[i] = 0; + } + if (st->filt_len > olen) + { + /* If the new filter length is still bigger than the "augmented" length */ + /* Copy data going backward */ + for (j=0;jmem[i*st->mem_alloc_size+(st->filt_len-2-j)] = st->mem[i*st->mem_alloc_size+(olen-2-j)]; + /* Then put zeros for lack of anything better */ + for (;jfilt_len-1;j++) + st->mem[i*st->mem_alloc_size+(st->filt_len-2-j)] = 0; + /* Adjust last_sample */ + st->last_sample[i] += (st->filt_len - olen)/2; + } else { + /* Put back some of the magic! */ + st->magic_samples[i] = (olen - st->filt_len)/2; + for (j=0;jfilt_len-1+st->magic_samples[i];j++) + st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]]; + } + } + } else if (st->filt_len < old_length) + { + spx_uint32_t i; + /* Reduce filter length, this a bit tricky. We need to store some of the memory as "magic" + samples so they can be used directly as input the next time(s) */ + for (i=0;inb_channels;i++) + { + spx_uint32_t j; + spx_uint32_t old_magic = st->magic_samples[i]; + st->magic_samples[i] = (old_length - st->filt_len)/2; + /* We must copy some of the memory that's no longer used */ + /* Copy data going backward */ + for (j=0;jfilt_len-1+st->magic_samples[i]+old_magic;j++) + st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]]; + st->magic_samples[i] += old_magic; + } + } + +} + +EXPORT SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err) +{ + return speex_resampler_init_frac(nb_channels, in_rate, out_rate, in_rate, out_rate, quality, err); +} + +EXPORT SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err) +{ + spx_uint32_t i; + SpeexResamplerState *st; + if (quality > 10 || quality < 0) + { + if (err) + *err = RESAMPLER_ERR_INVALID_ARG; + return NULL; + } + st = (SpeexResamplerState *)speex_alloc(sizeof(SpeexResamplerState)); + st->initialised = 0; + st->started = 0; + st->in_rate = 0; + st->out_rate = 0; + st->num_rate = 0; + st->den_rate = 0; + st->quality = -1; + st->sinc_table_length = 0; + st->mem_alloc_size = 0; + st->filt_len = 0; + st->mem = 0; + st->resampler_ptr = 0; + + st->cutoff = 1.f; + st->nb_channels = nb_channels; + st->in_stride = 1; + st->out_stride = 1; + +#ifdef FIXED_POINT + st->buffer_size = 160; +#else + st->buffer_size = 160; +#endif + + /* Per channel data */ + st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(int)); + st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int)); + st->samp_frac_num = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int)); + for (i=0;ilast_sample[i] = 0; + st->magic_samples[i] = 0; + st->samp_frac_num[i] = 0; + } + + speex_resampler_set_quality(st, quality); + speex_resampler_set_rate_frac(st, ratio_num, ratio_den, in_rate, out_rate); + + + update_filter(st); + + st->initialised = 1; + if (err) + *err = RESAMPLER_ERR_SUCCESS; + + return st; +} + +EXPORT void speex_resampler_destroy(SpeexResamplerState *st) +{ + speex_free(st->mem); + speex_free(st->sinc_table); + speex_free(st->last_sample); + speex_free(st->magic_samples); + speex_free(st->samp_frac_num); + speex_free(st); +} + +static int speex_resampler_process_native(SpeexResamplerState *st, spx_uint32_t channel_index, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) +{ + int j=0; + const int N = st->filt_len; + int out_sample = 0; + spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size; + spx_uint32_t ilen; + + st->started = 1; + + /* Call the right resampler through the function ptr */ + out_sample = st->resampler_ptr(st, channel_index, mem, in_len, out, out_len); + + if (st->last_sample[channel_index] < (spx_int32_t)*in_len) + *in_len = st->last_sample[channel_index]; + *out_len = out_sample; + st->last_sample[channel_index] -= *in_len; + + ilen = *in_len; + + for(j=0;jmagic_samples[channel_index]; + spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size; + const int N = st->filt_len; + + speex_resampler_process_native(st, channel_index, &tmp_in_len, *out, &out_len); + + st->magic_samples[channel_index] -= tmp_in_len; + + /* If we couldn't process all "magic" input samples, save the rest for next time */ + if (st->magic_samples[channel_index]) + { + spx_uint32_t i; + for (i=0;imagic_samples[channel_index];i++) + mem[N-1+i]=mem[N-1+i+tmp_in_len]; + } + *out += out_len*st->out_stride; + return out_len; +} + +#ifdef FIXED_POINT +EXPORT int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len) +#else +EXPORT int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) +#endif +{ + int j; + spx_uint32_t ilen = *in_len; + spx_uint32_t olen = *out_len; + spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size; + const int filt_offs = st->filt_len - 1; + const spx_uint32_t xlen = st->mem_alloc_size - filt_offs; + const int istride = st->in_stride; + + if (st->magic_samples[channel_index]) + olen -= speex_resampler_magic(st, channel_index, &out, olen); + if (! st->magic_samples[channel_index]) { + while (ilen && olen) { + spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen; + spx_uint32_t ochunk = olen; + + if (in) { + for(j=0;jout_stride; + if (in) + in += ichunk * istride; + } + } + *in_len -= ilen; + *out_len -= olen; + return RESAMPLER_ERR_SUCCESS; +} + +#ifdef FIXED_POINT +EXPORT int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) +#else +EXPORT int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len) +#endif +{ + int j; + const int istride_save = st->in_stride; + const int ostride_save = st->out_stride; + spx_uint32_t ilen = *in_len; + spx_uint32_t olen = *out_len; + spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size; + const spx_uint32_t xlen = st->mem_alloc_size - (st->filt_len - 1); +#ifdef VAR_ARRAYS + const unsigned int ylen = (olen < FIXED_STACK_ALLOC) ? olen : FIXED_STACK_ALLOC; + VARDECL(spx_word16_t *ystack); + ALLOC(ystack, ylen, spx_word16_t); +#else + const unsigned int ylen = FIXED_STACK_ALLOC; + spx_word16_t ystack[FIXED_STACK_ALLOC]; +#endif + + st->out_stride = 1; + + while (ilen && olen) { + spx_word16_t *y = ystack; + spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen; + spx_uint32_t ochunk = (olen > ylen) ? ylen : olen; + spx_uint32_t omagic = 0; + + if (st->magic_samples[channel_index]) { + omagic = speex_resampler_magic(st, channel_index, &y, ochunk); + ochunk -= omagic; + olen -= omagic; + } + if (! st->magic_samples[channel_index]) { + if (in) { + for(j=0;jfilt_len-1]=WORD2INT(in[j*istride_save]); +#else + x[j+st->filt_len-1]=in[j*istride_save]; +#endif + } else { + for(j=0;jfilt_len-1]=0; + } + + speex_resampler_process_native(st, channel_index, &ichunk, y, &ochunk); + } else { + ichunk = 0; + ochunk = 0; + } + + for (j=0;jout_stride = ostride_save; + *in_len -= ilen; + *out_len -= olen; + + return RESAMPLER_ERR_SUCCESS; +} + +EXPORT int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) +{ + spx_uint32_t i; + int istride_save, ostride_save; + spx_uint32_t bak_len = *out_len; + istride_save = st->in_stride; + ostride_save = st->out_stride; + st->in_stride = st->out_stride = st->nb_channels; + for (i=0;inb_channels;i++) + { + *out_len = bak_len; + if (in != NULL) + speex_resampler_process_float(st, i, in+i, in_len, out+i, out_len); + else + speex_resampler_process_float(st, i, NULL, in_len, out+i, out_len); + } + st->in_stride = istride_save; + st->out_stride = ostride_save; + return RESAMPLER_ERR_SUCCESS; +} + +EXPORT int speex_resampler_process_interleaved_int(SpeexResamplerState *st, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len) +{ + spx_uint32_t i; + int istride_save, ostride_save; + spx_uint32_t bak_len = *out_len; + istride_save = st->in_stride; + ostride_save = st->out_stride; + st->in_stride = st->out_stride = st->nb_channels; + for (i=0;inb_channels;i++) + { + *out_len = bak_len; + if (in != NULL) + speex_resampler_process_int(st, i, in+i, in_len, out+i, out_len); + else + speex_resampler_process_int(st, i, NULL, in_len, out+i, out_len); + } + st->in_stride = istride_save; + st->out_stride = ostride_save; + return RESAMPLER_ERR_SUCCESS; +} + +EXPORT int speex_resampler_set_rate(SpeexResamplerState *st, spx_uint32_t in_rate, spx_uint32_t out_rate) +{ + return speex_resampler_set_rate_frac(st, in_rate, out_rate, in_rate, out_rate); +} + +EXPORT void speex_resampler_get_rate(SpeexResamplerState *st, spx_uint32_t *in_rate, spx_uint32_t *out_rate) +{ + *in_rate = st->in_rate; + *out_rate = st->out_rate; +} + +EXPORT int speex_resampler_set_rate_frac(SpeexResamplerState *st, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate) +{ + spx_uint32_t fact; + spx_uint32_t old_den; + spx_uint32_t i; + if (st->in_rate == in_rate && st->out_rate == out_rate && st->num_rate == ratio_num && st->den_rate == ratio_den) + return RESAMPLER_ERR_SUCCESS; + + old_den = st->den_rate; + st->in_rate = in_rate; + st->out_rate = out_rate; + st->num_rate = ratio_num; + st->den_rate = ratio_den; + /* FIXME: This is terribly inefficient, but who cares (at least for now)? */ + for (fact=2;fact<=IMIN(st->num_rate, st->den_rate);fact++) + { + while ((st->num_rate % fact == 0) && (st->den_rate % fact == 0)) + { + st->num_rate /= fact; + st->den_rate /= fact; + } + } + + if (old_den > 0) + { + for (i=0;inb_channels;i++) + { + st->samp_frac_num[i]=st->samp_frac_num[i]*st->den_rate/old_den; + /* Safety net */ + if (st->samp_frac_num[i] >= st->den_rate) + st->samp_frac_num[i] = st->den_rate-1; + } + } + + if (st->initialised) + update_filter(st); + return RESAMPLER_ERR_SUCCESS; +} + +EXPORT void speex_resampler_get_ratio(SpeexResamplerState *st, spx_uint32_t *ratio_num, spx_uint32_t *ratio_den) +{ + *ratio_num = st->num_rate; + *ratio_den = st->den_rate; +} + +EXPORT int speex_resampler_set_quality(SpeexResamplerState *st, int quality) +{ + if (quality > 10 || quality < 0) + return RESAMPLER_ERR_INVALID_ARG; + if (st->quality == quality) + return RESAMPLER_ERR_SUCCESS; + st->quality = quality; + if (st->initialised) + update_filter(st); + return RESAMPLER_ERR_SUCCESS; +} + +EXPORT void speex_resampler_get_quality(SpeexResamplerState *st, int *quality) +{ + *quality = st->quality; +} + +EXPORT void speex_resampler_set_input_stride(SpeexResamplerState *st, spx_uint32_t stride) +{ + st->in_stride = stride; +} + +EXPORT void speex_resampler_get_input_stride(SpeexResamplerState *st, spx_uint32_t *stride) +{ + *stride = st->in_stride; +} + +EXPORT void speex_resampler_set_output_stride(SpeexResamplerState *st, spx_uint32_t stride) +{ + st->out_stride = stride; +} + +EXPORT void speex_resampler_get_output_stride(SpeexResamplerState *st, spx_uint32_t *stride) +{ + *stride = st->out_stride; +} + +EXPORT int speex_resampler_get_input_latency(SpeexResamplerState *st) +{ + return st->filt_len / 2; +} + +EXPORT int speex_resampler_get_output_latency(SpeexResamplerState *st) +{ + return ((st->filt_len / 2) * st->den_rate + (st->num_rate >> 1)) / st->num_rate; +} + +EXPORT int speex_resampler_skip_zeros(SpeexResamplerState *st) +{ + spx_uint32_t i; + for (i=0;inb_channels;i++) + st->last_sample[i] = st->filt_len/2; + return RESAMPLER_ERR_SUCCESS; +} + +EXPORT int speex_resampler_reset_mem(SpeexResamplerState *st) +{ + spx_uint32_t i; + for (i=0;inb_channels*(st->filt_len-1);i++) + st->mem[i] = 0; + return RESAMPLER_ERR_SUCCESS; +} + +EXPORT const char *speex_resampler_strerror(int err) +{ + switch (err) + { + case RESAMPLER_ERR_SUCCESS: + return "Success."; + case RESAMPLER_ERR_ALLOC_FAILED: + return "Memory allocation failed."; + case RESAMPLER_ERR_BAD_STATE: + return "Bad resampler state."; + case RESAMPLER_ERR_INVALID_ARG: + return "Invalid argument."; + case RESAMPLER_ERR_PTR_OVERLAP: + return "Input and output buffers overlap."; + default: + return "Unknown error. Bad error code or strange version mismatch."; + } +} diff --git a/lib/libspeex/speex/speex_resampler.h b/lib/libspeex/speex/speex_resampler.h new file mode 100644 index 0000000000..54eef8d7b8 --- /dev/null +++ b/lib/libspeex/speex/speex_resampler.h @@ -0,0 +1,340 @@ +/* Copyright (C) 2007 Jean-Marc Valin + + File: speex_resampler.h + Resampling code + + The design goals of this code are: + - Very fast algorithm + - Low memory requirement + - Good *perceptual* quality (and not best SNR) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef SPEEX_RESAMPLER_H +#define SPEEX_RESAMPLER_H + +#ifdef OUTSIDE_SPEEX + +/********* WARNING: MENTAL SANITY ENDS HERE *************/ + +/* If the resampler is defined outside of Speex, we change the symbol names so that + there won't be any clash if linking with Speex later on. */ + +/* #define RANDOM_PREFIX your software name here */ +#ifndef RANDOM_PREFIX +#error "Please define RANDOM_PREFIX (above) to something specific to your project to prevent symbol name clashes" +#endif + +#define CAT_PREFIX2(a,b) a ## b +#define CAT_PREFIX(a,b) CAT_PREFIX2(a, b) + +#define speex_resampler_init CAT_PREFIX(RANDOM_PREFIX,_resampler_init) +#define speex_resampler_init_frac CAT_PREFIX(RANDOM_PREFIX,_resampler_init_frac) +#define speex_resampler_destroy CAT_PREFIX(RANDOM_PREFIX,_resampler_destroy) +#define speex_resampler_process_float CAT_PREFIX(RANDOM_PREFIX,_resampler_process_float) +#define speex_resampler_process_int CAT_PREFIX(RANDOM_PREFIX,_resampler_process_int) +#define speex_resampler_process_interleaved_float CAT_PREFIX(RANDOM_PREFIX,_resampler_process_interleaved_float) +#define speex_resampler_process_interleaved_int CAT_PREFIX(RANDOM_PREFIX,_resampler_process_interleaved_int) +#define speex_resampler_set_rate CAT_PREFIX(RANDOM_PREFIX,_resampler_set_rate) +#define speex_resampler_get_rate CAT_PREFIX(RANDOM_PREFIX,_resampler_get_rate) +#define speex_resampler_set_rate_frac CAT_PREFIX(RANDOM_PREFIX,_resampler_set_rate_frac) +#define speex_resampler_get_ratio CAT_PREFIX(RANDOM_PREFIX,_resampler_get_ratio) +#define speex_resampler_set_quality CAT_PREFIX(RANDOM_PREFIX,_resampler_set_quality) +#define speex_resampler_get_quality CAT_PREFIX(RANDOM_PREFIX,_resampler_get_quality) +#define speex_resampler_set_input_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_set_input_stride) +#define speex_resampler_get_input_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_input_stride) +#define speex_resampler_set_output_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_set_output_stride) +#define speex_resampler_get_output_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_output_stride) +#define speex_resampler_get_input_latency CAT_PREFIX(RANDOM_PREFIX,_resampler_get_input_latency) +#define speex_resampler_get_output_latency CAT_PREFIX(RANDOM_PREFIX,_resampler_get_output_latency) +#define speex_resampler_skip_zeros CAT_PREFIX(RANDOM_PREFIX,_resampler_skip_zeros) +#define speex_resampler_reset_mem CAT_PREFIX(RANDOM_PREFIX,_resampler_reset_mem) +#define speex_resampler_strerror CAT_PREFIX(RANDOM_PREFIX,_resampler_strerror) + +#define spx_int16_t short +#define spx_int32_t int +#define spx_uint16_t unsigned short +#define spx_uint32_t unsigned int + +#else /* OUTSIDE_SPEEX */ + +#include "speex/speex_types.h" + +#endif /* OUTSIDE_SPEEX */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define SPEEX_RESAMPLER_QUALITY_MAX 10 +#define SPEEX_RESAMPLER_QUALITY_MIN 0 +#define SPEEX_RESAMPLER_QUALITY_DEFAULT 4 +#define SPEEX_RESAMPLER_QUALITY_VOIP 3 +#define SPEEX_RESAMPLER_QUALITY_DESKTOP 5 + +enum { + RESAMPLER_ERR_SUCCESS = 0, + RESAMPLER_ERR_ALLOC_FAILED = 1, + RESAMPLER_ERR_BAD_STATE = 2, + RESAMPLER_ERR_INVALID_ARG = 3, + RESAMPLER_ERR_PTR_OVERLAP = 4, + + RESAMPLER_ERR_MAX_ERROR +}; + +struct SpeexResamplerState_; +typedef struct SpeexResamplerState_ SpeexResamplerState; + +/** Create a new resampler with integer input and output rates. + * @param nb_channels Number of channels to be processed + * @param in_rate Input sampling rate (integer number of Hz). + * @param out_rate Output sampling rate (integer number of Hz). + * @param quality Resampling quality between 0 and 10, where 0 has poor quality + * and 10 has very high quality. + * @return Newly created resampler state + * @retval NULL Error: not enough memory + */ +SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, + spx_uint32_t in_rate, + spx_uint32_t out_rate, + int quality, + int *err); + +/** Create a new resampler with fractional input/output rates. The sampling + * rate ratio is an arbitrary rational number with both the numerator and + * denominator being 32-bit integers. + * @param nb_channels Number of channels to be processed + * @param ratio_num Numerator of the sampling rate ratio + * @param ratio_den Denominator of the sampling rate ratio + * @param in_rate Input sampling rate rounded to the nearest integer (in Hz). + * @param out_rate Output sampling rate rounded to the nearest integer (in Hz). + * @param quality Resampling quality between 0 and 10, where 0 has poor quality + * and 10 has very high quality. + * @return Newly created resampler state + * @retval NULL Error: not enough memory + */ +SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, + spx_uint32_t ratio_num, + spx_uint32_t ratio_den, + spx_uint32_t in_rate, + spx_uint32_t out_rate, + int quality, + int *err); + +/** Destroy a resampler state. + * @param st Resampler state + */ +void speex_resampler_destroy(SpeexResamplerState *st); + +/** Resample a float array. The input and output buffers must *not* overlap. + * @param st Resampler state + * @param channel_index Index of the channel to process for the multi-channel + * base (0 otherwise) + * @param in Input buffer + * @param in_len Number of input samples in the input buffer. Returns the + * number of samples processed + * @param out Output buffer + * @param out_len Size of the output buffer. Returns the number of samples written + */ +int speex_resampler_process_float(SpeexResamplerState *st, + spx_uint32_t channel_index, + const float *in, + spx_uint32_t *in_len, + float *out, + spx_uint32_t *out_len); + +/** Resample an int array. The input and output buffers must *not* overlap. + * @param st Resampler state + * @param channel_index Index of the channel to process for the multi-channel + * base (0 otherwise) + * @param in Input buffer + * @param in_len Number of input samples in the input buffer. Returns the number + * of samples processed + * @param out Output buffer + * @param out_len Size of the output buffer. Returns the number of samples written + */ +int speex_resampler_process_int(SpeexResamplerState *st, + spx_uint32_t channel_index, + const spx_int16_t *in, + spx_uint32_t *in_len, + spx_int16_t *out, + spx_uint32_t *out_len); + +/** Resample an interleaved float array. The input and output buffers must *not* overlap. + * @param st Resampler state + * @param in Input buffer + * @param in_len Number of input samples in the input buffer. Returns the number + * of samples processed. This is all per-channel. + * @param out Output buffer + * @param out_len Size of the output buffer. Returns the number of samples written. + * This is all per-channel. + */ +int speex_resampler_process_interleaved_float(SpeexResamplerState *st, + const float *in, + spx_uint32_t *in_len, + float *out, + spx_uint32_t *out_len); + +/** Resample an interleaved int array. The input and output buffers must *not* overlap. + * @param st Resampler state + * @param in Input buffer + * @param in_len Number of input samples in the input buffer. Returns the number + * of samples processed. This is all per-channel. + * @param out Output buffer + * @param out_len Size of the output buffer. Returns the number of samples written. + * This is all per-channel. + */ +int speex_resampler_process_interleaved_int(SpeexResamplerState *st, + const spx_int16_t *in, + spx_uint32_t *in_len, + spx_int16_t *out, + spx_uint32_t *out_len); + +/** Set (change) the input/output sampling rates (integer value). + * @param st Resampler state + * @param in_rate Input sampling rate (integer number of Hz). + * @param out_rate Output sampling rate (integer number of Hz). + */ +int speex_resampler_set_rate(SpeexResamplerState *st, + spx_uint32_t in_rate, + spx_uint32_t out_rate); + +/** Get the current input/output sampling rates (integer value). + * @param st Resampler state + * @param in_rate Input sampling rate (integer number of Hz) copied. + * @param out_rate Output sampling rate (integer number of Hz) copied. + */ +void speex_resampler_get_rate(SpeexResamplerState *st, + spx_uint32_t *in_rate, + spx_uint32_t *out_rate); + +/** Set (change) the input/output sampling rates and resampling ratio + * (fractional values in Hz supported). + * @param st Resampler state + * @param ratio_num Numerator of the sampling rate ratio + * @param ratio_den Denominator of the sampling rate ratio + * @param in_rate Input sampling rate rounded to the nearest integer (in Hz). + * @param out_rate Output sampling rate rounded to the nearest integer (in Hz). + */ +int speex_resampler_set_rate_frac(SpeexResamplerState *st, + spx_uint32_t ratio_num, + spx_uint32_t ratio_den, + spx_uint32_t in_rate, + spx_uint32_t out_rate); + +/** Get the current resampling ratio. This will be reduced to the least + * common denominator. + * @param st Resampler state + * @param ratio_num Numerator of the sampling rate ratio copied + * @param ratio_den Denominator of the sampling rate ratio copied + */ +void speex_resampler_get_ratio(SpeexResamplerState *st, + spx_uint32_t *ratio_num, + spx_uint32_t *ratio_den); + +/** Set (change) the conversion quality. + * @param st Resampler state + * @param quality Resampling quality between 0 and 10, where 0 has poor + * quality and 10 has very high quality. + */ +int speex_resampler_set_quality(SpeexResamplerState *st, + int quality); + +/** Get the conversion quality. + * @param st Resampler state + * @param quality Resampling quality between 0 and 10, where 0 has poor + * quality and 10 has very high quality. + */ +void speex_resampler_get_quality(SpeexResamplerState *st, + int *quality); + +/** Set (change) the input stride. + * @param st Resampler state + * @param stride Input stride + */ +void speex_resampler_set_input_stride(SpeexResamplerState *st, + spx_uint32_t stride); + +/** Get the input stride. + * @param st Resampler state + * @param stride Input stride copied + */ +void speex_resampler_get_input_stride(SpeexResamplerState *st, + spx_uint32_t *stride); + +/** Set (change) the output stride. + * @param st Resampler state + * @param stride Output stride + */ +void speex_resampler_set_output_stride(SpeexResamplerState *st, + spx_uint32_t stride); + +/** Get the output stride. + * @param st Resampler state copied + * @param stride Output stride + */ +void speex_resampler_get_output_stride(SpeexResamplerState *st, + spx_uint32_t *stride); + +/** Get the latency in input samples introduced by the resampler. + * @param st Resampler state + */ +int speex_resampler_get_input_latency(SpeexResamplerState *st); + +/** Get the latency in output samples introduced by the resampler. + * @param st Resampler state + */ +int speex_resampler_get_output_latency(SpeexResamplerState *st); + +/** Make sure that the first samples to go out of the resamplers don't have + * leading zeros. This is only useful before starting to use a newly created + * resampler. It is recommended to use that when resampling an audio file, as + * it will generate a file with the same length. For real-time processing, + * it is probably easier not to use this call (so that the output duration + * is the same for the first frame). + * @param st Resampler state + */ +int speex_resampler_skip_zeros(SpeexResamplerState *st); + +/** Reset a resampler so a new (unrelated) stream can be processed. + * @param st Resampler state + */ +int speex_resampler_reset_mem(SpeexResamplerState *st); + +/** Returns the English meaning for an error code + * @param err Error code + * @return English string + */ +const char *speex_resampler_strerror(int err); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/libspeex/speex/speex_types.h b/lib/libspeex/speex/speex_types.h new file mode 100644 index 0000000000..852fed801d --- /dev/null +++ b/lib/libspeex/speex/speex_types.h @@ -0,0 +1,126 @@ +/* speex_types.h taken from libogg */ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: #ifdef jail to whip a few platforms into the UNIX ideal. + last mod: $Id: os_types.h 7524 2004-08-11 04:20:36Z conrad $ + + ********************************************************************/ +/** + @file speex_types.h + @brief Speex types +*/ +#ifndef _SPEEX_TYPES_H +#define _SPEEX_TYPES_H + +#if defined(_WIN32) + +# if defined(__CYGWIN__) +# include <_G_config.h> + typedef _G_int32_t spx_int32_t; + typedef _G_uint32_t spx_uint32_t; + typedef _G_int16_t spx_int16_t; + typedef _G_uint16_t spx_uint16_t; +# elif defined(__MINGW32__) + typedef short spx_int16_t; + typedef unsigned short spx_uint16_t; + typedef int spx_int32_t; + typedef unsigned int spx_uint32_t; +# elif defined(__MWERKS__) + typedef int spx_int32_t; + typedef unsigned int spx_uint32_t; + typedef short spx_int16_t; + typedef unsigned short spx_uint16_t; +# else + /* MSVC/Borland */ + typedef __int32 spx_int32_t; + typedef unsigned __int32 spx_uint32_t; + typedef __int16 spx_int16_t; + typedef unsigned __int16 spx_uint16_t; +# endif + +#elif defined(__MACOS__) + +# include + typedef SInt16 spx_int16_t; + typedef UInt16 spx_uint16_t; + typedef SInt32 spx_int32_t; + typedef UInt32 spx_uint32_t; + +#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */ + +# include + typedef int16_t spx_int16_t; + typedef u_int16_t spx_uint16_t; + typedef int32_t spx_int32_t; + typedef u_int32_t spx_uint32_t; + +#elif defined(__BEOS__) + + /* Be */ +# include + typedef int16_t spx_int16_t; + typedef u_int16_t spx_uint16_t; + typedef int32_t spx_int32_t; + typedef u_int32_t spx_uint32_t; + +#elif defined (__EMX__) + + /* OS/2 GCC */ + typedef short spx_int16_t; + typedef unsigned short spx_uint16_t; + typedef int spx_int32_t; + typedef unsigned int spx_uint32_t; + +#elif defined (DJGPP) + + /* DJGPP */ + typedef short spx_int16_t; + typedef int spx_int32_t; + typedef unsigned int spx_uint32_t; + +#elif defined(R5900) + + /* PS2 EE */ + typedef int spx_int32_t; + typedef unsigned spx_uint32_t; + typedef short spx_int16_t; + +#elif defined(__SYMBIAN32__) + + /* Symbian GCC */ + typedef signed short spx_int16_t; + typedef unsigned short spx_uint16_t; + typedef signed int spx_int32_t; + typedef unsigned int spx_uint32_t; + +#elif defined(CONFIG_TI_C54X) || defined (CONFIG_TI_C55X) + + typedef short spx_int16_t; + typedef unsigned short spx_uint16_t; + typedef long spx_int32_t; + typedef unsigned long spx_uint32_t; + +#elif defined(CONFIG_TI_C6X) + + typedef short spx_int16_t; + typedef unsigned short spx_uint16_t; + typedef int spx_int32_t; + typedef unsigned int spx_uint32_t; + +#else + +# include + +#endif + +#endif /* _SPEEX_TYPES_H */ diff --git a/lib/libspeex/stack_alloc.h b/lib/libspeex/stack_alloc.h new file mode 100644 index 0000000000..f2a10921c5 --- /dev/null +++ b/lib/libspeex/stack_alloc.h @@ -0,0 +1,115 @@ +/* Copyright (C) 2002 Jean-Marc Valin */ +/** + @file stack_alloc.h + @brief Temporary memory allocation on stack +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef STACK_ALLOC_H +#define STACK_ALLOC_H + +#ifdef USE_ALLOCA +# ifdef WIN32 +# include +# else +# ifdef HAVE_ALLOCA_H +# include +# else +# include +# endif +# endif +#endif + +/** + * @def ALIGN(stack, size) + * + * Aligns the stack to a 'size' boundary + * + * @param stack Stack + * @param size New size boundary + */ + +/** + * @def PUSH(stack, size, type) + * + * Allocates 'size' elements of type 'type' on the stack + * + * @param stack Stack + * @param size Number of elements + * @param type Type of element + */ + +/** + * @def VARDECL(var) + * + * Declare variable on stack + * + * @param var Variable to declare + */ + +/** + * @def ALLOC(var, size, type) + * + * Allocate 'size' elements of 'type' on stack + * + * @param var Name of variable to allocate + * @param size Number of elements + * @param type Type of element + */ + +#ifdef ENABLE_VALGRIND + +#include + +#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1)) + +#define PUSH(stack, size, type) (VALGRIND_MAKE_NOACCESS(stack, 1000),ALIGN((stack),sizeof(type)),VALGRIND_MAKE_WRITABLE(stack, ((size)*sizeof(type))),(stack)+=((size)*sizeof(type)),(type*)((stack)-((size)*sizeof(type)))) + +#else + +#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1)) + +#define PUSH(stack, size, type) (ALIGN((stack),sizeof(type)),(stack)+=((size)*sizeof(type)),(type*)((stack)-((size)*sizeof(type)))) + +#endif + +#if defined(VAR_ARRAYS) +#define VARDECL(var) +#define ALLOC(var, size, type) type var[size] +#elif defined(USE_ALLOCA) +#define VARDECL(var) var +#define ALLOC(var, size, type) var = _alloca(sizeof(type)*(size)) +#else +#define VARDECL(var) var +#define ALLOC(var, size, type) var = PUSH(stack, size, type) +#endif + + +#endif diff --git a/lodepng/lodepng.c b/lib/lodepng/lodepng.c similarity index 100% rename from lodepng/lodepng.c rename to lib/lodepng/lodepng.c diff --git a/lodepng/lodepng.h b/lib/lodepng/lodepng.h similarity index 100% rename from lodepng/lodepng.h rename to lib/lodepng/lodepng.h diff --git a/projects/openrct2.vcxproj b/projects/openrct2.vcxproj index 00a5fd1e84..5d856b42d7 100644 --- a/projects/openrct2.vcxproj +++ b/projects/openrct2.vcxproj @@ -14,133 +14,6 @@ Win32 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -152,6 +25,171 @@ + + + + + + + + + + + + TurnOffAllWarnings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {D24D94F6-2A74-480C-B512-629C306CE92F} @@ -183,14 +221,14 @@ - $(SolutionDir)..\lodepng;$(SolutionDir)..\sdl\include;$(IncludePath) + $(SolutionDir)..\lodepng;$(SolutionDir)..\sdl\include;$(SolutionDir)..\libspeex;$(IncludePath) $(SolutionDir)..\sdl\lib\x86;$(LibraryPath) $(SolutionDir)..\build\$(Configuration)\ $(SolutionDir)..\obj\$(Configuration)\ - $(SolutionDir)..\lodepng;$(SolutionDir)..\sdl\include;$(IncludePath) - $(SolutionDir)..\sdl\lib\x86;$(LibraryPath) + $(SolutionDir)..\lib;$(SolutionDir)..\lib\libspeex;$(SolutionDir)..\lib\sdl\include;$(IncludePath) + $(SolutionDir)..\lib\sdl\lib\x86;$(LibraryPath) $(SolutionDir)..\build\$(Configuration)\ $(SolutionDir)..\obj\$(Configuration)\ @@ -200,7 +238,7 @@ Disabled true 1Byte - _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;HAVE_CONFIG_H;_USE_MATH_DEFINES;%(PreprocessorDefinitions) true @@ -221,7 +259,8 @@ false - _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;HAVE_CONFIG_H;_USE_MATH_DEFINES;%(PreprocessorDefinitions) + $(IntDir)fake\%(RelativeDir) true diff --git a/projects/openrct2.vcxproj.filters b/projects/openrct2.vcxproj.filters index 525392db46..e1b4435a08 100644 --- a/projects/openrct2.vcxproj.filters +++ b/projects/openrct2.vcxproj.filters @@ -1,400 +1,64 @@  - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - {611458dc-7dd2-4c37-af0f-306cf9d85fb9} + + {29bd2abb-0a50-4c58-9031-bee3f966b249} - + + {e9219aff-1bb5-4065-8204-427a97344a43} + + + {3c824fc4-8242-4127-a4b4-248435ff9058} + + + {4c8348c7-dfe9-4368-9d87-29733fe5950a} + + + {8e15cd5b-d7a7-4bda-a58a-e1158ad6ffb4} + + {ee2e3a6f-1209-407b-8000-a6a4b88d28d9} - + {b344ca0f-b412-4924-be08-54bb6f83c3dd} - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Windows - - - Windows - - - Windows - - - Windows - - - Source Files - - - Windows - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Windows - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Windows - - - Windows - - - Windows - - - Windows - - - Windows - - - Windows - - - Source Files - - - Windows - - - Windows - - - Source Files - - - Windows - - - Windows - - - Source Files - - - Windows - - - Source Files - - - Windows - - - Windows - - - Windows - - - Windows - - - Source Files - - - Windows - - - Windows - - - Windows - - - Windows - - - Windows - - - Windows - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Windows - - - Source Files - - - Source Files - - - Windows - - - Source Files - - - Windows - - - Windows - - - Source Files - - - Windows - - - Source Files - - - Windows - + + {8a9b8831-4ba9-4104-b13f-949981e10c22} + + + {97950d17-f655-49bb-85f4-309feb332b02} + + + {9ac1caf2-4edc-4237-b441-16cc8923d9e3} + + + {7f7d04b9-188e-4086-a2a2-5b7b2eb2310b} + + + {22415bda-c4d8-425c-bd06-4c5bbdffe6d7} + + + {3af99868-3e47-4832-bf01-409aec0b08e7} + + + {2f881d9d-1f7e-40bf-ad3d-92db3a31ce90} + + + {6c8e1ad1-9d13-41f8-a9db-64501ad65503} + + + {81716f5d-b396-4a82-a450-76fee56d982b} + + + {209155b8-2f61-4e25-ab86-c8aa36357abd} + + + {51e38783-5334-464c-8f90-61d725dc8013} + @@ -403,25 +67,538 @@ - Data\Language + Source\Data\Language - Data\Language + Source\Data\Language - Data\Language + Source\Data\Language - Data\Language + Source\Data\Language - Data\Language + Source\Data\Language - Data\Language + Source\Data\Language - Data\Language + Source\Data\Language + + + Source\Data\Language + + + Source\Management + + + Source\Management + + + Source\Management + + + Source\Management + + + Source\Audio + + + Source\Audio + + + Source\Interface + + + Source\Interface + + + Source\Interface + + + Source\Interface + + + Source\Interface + + + Source\World + + + Source\World + + + Source\World + + + Source\World + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + Source\Localisation + + + Source\Localisation + + + Source\Platform + + + Source\Ride + + + Source\Ride + + + Source\Ride + + + Source\Ride + + + Source\Ride + + + Source\Util + + + Source\Util + + + Source + + + Source + + + Source + + + Source + + + Source + + + Source + + + Source + + + Source + + + Source + + + Source + + + Source + + + Source + + + Source + + + Source\Localisation + + + Source\Drawing + + + Source\Drawing + + + Source\Drawing + + + Source\Drawing + + + Source\Drawing + + + Source\Localisation + + + Source\Platform + + + Source\Platform + + + Source\Platform + + + Source\Platform + + + Source\Localisation + + + Source\Peep + + + Source\Peep + + + Source\Management + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + + + + Source\Windows + + + Source\Windows + + + + + + Libraries\libspeex + + + + + + Libraries\lodepng + + + + + Libraries\libspeex + + + + Source\Drawing + + + + + Libraries\lodepng + + + + Libraries\libspeex + + + + + + Libraries\libspeex + + + + Libraries\lodepng + + + + + + Source\Management + + + Source\Management + + + Source\Management + + + Source\Management + + + Source\Audio + + + Source\Audio + + + Source\Interface + + + Source\Interface + + + Source\Interface + + + Source\Interface + + + Source\Interface + + + Source\World + + + Source\World + + + Source\World + + + Source\World + + + Source\World + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + Source\Windows + + + Source\Localisation + + + Source\Localisation + + + Source\Localisation + + + Source\Platform + + + Source\Ride + + + Source\Ride + + + Source\Ride + + + Source\Ride + + + Source\Ride + + + Source\Util + + + Source\Util + + + Source + + + Source + + + Source + + + Source + + + Source + + + Source + + + Source + + + Source + + + Source + + + Source + + + Source + + + Source + + + Source + + + Source + + + Source\Localisation + + + Source\Drawing + + + Source + + + Source\Localisation + + + Source\Platform + + + Source\Localisation + + + Libraries\lodepng + + + Libraries\libspeex + + + Libraries\libspeex + + + Libraries\libspeex + + + Libraries\libspeex + + + Libraries\libspeex\speex + + + Libraries\libspeex\speex + + + Source\Peep + + + Source\Peep + + + Source\Management + + \ No newline at end of file diff --git a/readme.md b/readme.md index 403ce159c5..be64612120 100644 --- a/readme.md +++ b/readme.md @@ -53,6 +53,8 @@ The aim is to completely decompile RollerCoaster Tycoon 2 into C so that cross-p # 2 Building the source code +Alternatively, a third-party offers [downloadable precompiled builds](https://openrct2.com/download). However, building the project is always recommended. + ## 2.1 Prerequisites ### Windows: - Windows XP / Vista / 7 / 8 diff --git a/src/addresses.h b/src/addresses.h index 19263023c3..f510eac542 100644 --- a/src/addresses.h +++ b/src/addresses.h @@ -41,6 +41,18 @@ #define RCT2_CALLPROC_4(address, a1, a2, a3, a4, v1, v2, v3, v4) RCT2_CALLFUNC_4(address, void, a1, a2, a3, a4, v1, v2, v3, v4) #define RCT2_CALLPROC_5(address, a1, a2, a3, a4, a5, v1, v2, v3, v4, v5) RCT2_CALLFUNC_5(address, void, a1, a2, a3, a4, a5, v1, v2, v3, v4, v5) +#pragma region Memory locations + +// The following memory locations represent memory in RCT2 that is still used +// by OpenRCT2. Only when the memory is no longer needed due to them being +// stored in a new C module or changed behaviour of code that used them. +// This generally can happen once all functions that referenced the location +// are implemented in C. Sometimes memory locations are still used even if +// they aren't directly referenced, for example when a game is saved and +// loaded, large chunks of data is read and written to. + +#define RCT2_ADDRESS_EASTEREGG_NAMES 0x00988C20 + #define RCT2_ADDRESS_RIDE_PROPERTIES 0x00997C9D #define RCT2_ADDRESS_LAND_TOOL_SIZE 0x009A9800 #define RCT2_ADDRESS_SAVE_PROMPT_MODE 0x009A9802 @@ -50,6 +62,8 @@ #define RCT2_ADDRESS_APP_PATH 0x009AA214 +#define RCT2_ADDRESS_DSOUND_GUID 0x009AAC5D + #define RCT2_ADDRESS_CONFIG_SOUND_SW_BUFFER 0x009AAC6E #define RCT2_ADDRESS_CONFIG_MUSIC 0x009AAC72 @@ -105,6 +119,8 @@ #define RCT2_ADDRESS_RUN_INTRO_TICK_PART 0x009AC319 +#define RCT2_ADDRESS_RIDE_ENTRIES 0x009ACFA4 + #define RCT2_ADDRESS_INSTALLED_OBJECT_LIST 0x009ADAE8 #define RCT2_ADDRESS_CURRENT_SOUND_DEVICE 0x009AF280 @@ -162,7 +178,7 @@ #define RCT2_ADDRESS_DSOUND_BUFFERS 0x009E1AB0 #define RCT2_ADDRESS_NUM_DSOUND_DEVICES 0x009E2B88 #define RCT2_ADDRESS_DSOUND_DEVICES 0x009E2B8C -#define RCT2_ADDRESS_SOUND_INFO_LIST_MAPPING 0x009E2B94 +#define RCT2_ADDRESS_SOUND_EFFECTS_MAPPING 0x009E2B94 #define RCT2_ADDRESS_SOUNDLIST_BEGIN 0x009E2B98 #define RCT2_ADDRESS_SOUNDLIST_END 0x009E2B9C #define RCT2_ADDRESS_DIRECTSOUND 0x009E2BA0 @@ -213,6 +229,8 @@ #define RCT2_ADDRESS_CONSTRUCT_PATH_FROM_Z 0x00F3EF8E #define RCT2_ADDRESS_CONSTRUCT_PATH_DIRECTION 0x00F3EF90 +#define RCT2_ADDRESS_VOLUME_ADJUST_ZOOM 0x00F438AC + #define RCT2_ADDRESS_STAFF_HIGHLIGHTED_INDEX 0x00F43908 #define RCT2_ADDRESS_CURRENT_MONTH_YEAR 0x00F663A8 @@ -277,6 +295,11 @@ #define RCT2_ADDRESS_SECURITY_COLOUR 0x01357BCF #define RCT2_ADDRESS_ACTIVE_RESEARCH_TYPES 0x01357CF2 +#define RCT2_ADDRESS_RESEARH_PROGRESS_STAGE 0x01357CF3 + +#define RCT2_ADDRESS_NEXT_RESEARCH_ITEM 0x013580E0 +#define RCT2_ADDRESS_RESEARH_PROGRESS 0x013580E4 +#define RCT2_ADDRESS_NEXT_RESEARCH_CATEGORY 0x013580E6 #define RCT2_ADDRESS_NEXT_RESEARCH_EXPECTED_DAY 0x013580E7 #define RCT2_ADDRESS_NEXT_RESEARCH_EXPECTED_MONTH 0x013580E8 @@ -286,6 +309,8 @@ #define RCT2_TOTAL_RIDE_VALUE 0x013580EE +#define RCT2_RESEARCH_ITEMS 0x01358844 + #define RCT2_ADDRESS_SCENARIO_NAME 0x0135920A #define RCT2_ADDRESS_SCENARIO_DETAILS 0x0135924A @@ -421,6 +446,28 @@ #define RCT2_ADDRESS_INPUT_QUEUE 0x01424340 +#define RCT2_ADDRESS_COMMON_FORMAT_ARGS 0x013CE952 + +#define RCT2_ADDRESS_STAFF_MODE_ARRAY 0x013CA672 + +#pragma endregion + +#pragma region Obsolete + +// The following addresses relate to memory locations that no longer used by +// OpenRCT2. This may be due to the data at those locations being stored in +// the new C modules or changed behaviour of code that used them. + +#define RCT2_ADDRESS_Y_RELATED_GLOBAL_1 0x9E3D12 //uint16 +#define RCT2_ADDRESS_Y_END_POINT_GLOBAL 0x9ABDAC //sint16 +#define RCT2_ADDRESS_Y_START_POINT_GLOBAL 0xEDF808 //sint16 +#define RCT2_ADDRESS_X_RELATED_GLOBAL_1 0x9E3D10 //uint16 +#define RCT2_ADDRESS_X_END_POINT_GLOBAL 0x9ABDA8 //sint16 +#define RCT2_ADDRESS_X_START_POINT_GLOBAL 0xEDF80C //sint16 +#define RCT2_ADDRESS_DPI_LINE_LENGTH_GLOBAL 0x9ABDB0 //uint16 width+pitch + +#pragma endregion + static void RCT2_CALLPROC_EBPSAFE(int address) { #ifdef _MSC_VER @@ -436,7 +483,7 @@ static void RCT2_CALLPROC_EBPSAFE(int address) #endif } -static void RCT2_CALLPROC_X(int address, int _eax, int _ebx, int _ecx, int _edx, int _esi, int _edi, int _ebp) +static int RCT2_CALLPROC_X(int address, int _eax, int _ebx, int _ecx, int _edx, int _esi, int _edi, int _ebp) { #ifdef _MSC_VER __asm { @@ -449,6 +496,7 @@ static void RCT2_CALLPROC_X(int address, int _eax, int _ebx, int _ecx, int _edx, mov edi, _edi mov ebp, _ebp call [esp] + lahf add esp, 4 } #else @@ -465,6 +513,7 @@ static void RCT2_CALLPROC_X(int address, int _eax, int _ebx, int _ecx, int _edx, mov edi, %[_edi] \n\ mov ebp, %[_ebp] \n\ call [esp] \n\ + lahf \n\ add esp, 4 \n\ pop ebp \n\ pop ebx \n\ diff --git a/src/audio.c b/src/audio/audio.c similarity index 72% rename from src/audio.c rename to src/audio/audio.c index fe46f41668..5ff65ffb31 100644 --- a/src/audio.c +++ b/src/audio/audio.c @@ -19,16 +19,22 @@ *****************************************************************************/ #include +#include "../addresses.h" +#include "../config.h" +#include "../interface/viewport.h" +#include "../interface/window.h" +#include "../platform/osinterface.h" +#include "../world/map.h" +#include "../world/sprite.h" #include "audio.h" -#include "addresses.h" -#include "config.h" -#include "rct2.h" -#include "sprite.h" -#include "viewport.h" -#include "window.h" +#include "mixer.h" int gAudioDeviceCount; audio_device *gAudioDevices = NULL; +rct_vehicle_sound gVehicleSoundList[AUDIO_MAX_VEHICLE_SOUNDS]; +rct_vehicle_sound_params gVehicleSoundParamsList[AUDIO_MAX_VEHICLE_SOUNDS]; +rct_vehicle_sound_params *gVehicleSoundParamsListEnd; +void* gMusicChannels[4]; void audio_init(int i) { @@ -96,12 +102,12 @@ int audio_release() * * rct2: 0x00404C45 */ -int unmap_sound_info() +int unmap_sound_effects() { - if (RCT2_GLOBAL(RCT2_ADDRESS_SOUND_INFO_LIST_MAPPING, LPVOID)) { + if (RCT2_GLOBAL(RCT2_ADDRESS_SOUND_EFFECTS_MAPPING, LPVOID)) { sound_stop_all(); - unmap_file(RCT2_GLOBAL(RCT2_ADDRESS_SOUND_INFO_LIST_MAPPING, LPVOID)); - RCT2_GLOBAL(RCT2_ADDRESS_SOUND_INFO_LIST_MAPPING, LPVOID) = 0; + unmap_file(RCT2_GLOBAL(RCT2_ADDRESS_SOUND_EFFECTS_MAPPING, LPVOID)); + RCT2_GLOBAL(RCT2_ADDRESS_SOUND_EFFECTS_MAPPING, LPVOID) = 0; return 1; } return 0; @@ -162,7 +168,7 @@ void audio_close() { if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SOUND_DEVICE, uint32) != -1) { stop_other_sounds(); - stop_peep_sounds(); + stop_crowd_sound(); stop_title_music(); if (RCT2_GLOBAL(0x009AF284, uint32) & (1 << 0)) { stop_ride_music(); @@ -171,7 +177,7 @@ void audio_close() RCT2_GLOBAL(0x014241BC, uint32) = 0; } RCT2_GLOBAL(0x014241BC, uint32) = 1; - unmap_sound_info(); + unmap_sound_effects(); audio_release(); RCT2_GLOBAL(0x014241BC, uint32) = 0; RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SOUND_DEVICE, uint32) = -1; @@ -215,14 +221,14 @@ int dsound_create_primary_buffer(int a, int device, int channels, int samples, i } dsdevice = &RCT2_GLOBAL(RCT2_ADDRESS_DSOUND_DEVICES, rct_dsdevice*)[device]; } - memset(&RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, rct_audio_info), 0, sizeof(rct_audio_info)); - RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, rct_audio_info).var_0 = 1; - RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, rct_audio_info).channels = channels; - RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, rct_audio_info).samples = samples; - RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, rct_audio_info).var_8 = samples * RCT2_GLOBAL(0x01425B4C, uint16); - RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, rct_audio_info).bytes = bits * channels / 8; - RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, rct_audio_info).bits = bits; - RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, rct_audio_info).var_E = 0; + memset(&RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, WAVEFORMATEX), 0, sizeof(WAVEFORMATEX)); + RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, WAVEFORMATEX).wFormatTag = 1; + RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, WAVEFORMATEX).nChannels = channels; + RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, WAVEFORMATEX).nSamplesPerSec = samples; + RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, WAVEFORMATEX).nAvgBytesPerSec = samples * RCT2_GLOBAL(0x01425B4C, uint16); + RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, WAVEFORMATEX).nBlockAlign = bits * channels / 8; + RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, WAVEFORMATEX).wBitsPerSample = bits; + RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, WAVEFORMATEX).cbSize = 0; DSBUFFERDESC bufferdesc; memset(&bufferdesc, 0, sizeof(bufferdesc)); bufferdesc.dwSize = sizeof(bufferdesc); @@ -343,13 +349,13 @@ LPVOID map_file(LPCSTR lpFileName, DWORD dwCreationDisposition, DWORD dwNumberOf * * rct2: 0x00404C1A */ -int map_sound_info(const char* filename) +int map_sound_effects(const char* filename) { - if (RCT2_GLOBAL(RCT2_ADDRESS_SOUND_INFO_LIST_MAPPING, LPVOID)) { + if (RCT2_GLOBAL(RCT2_ADDRESS_SOUND_EFFECTS_MAPPING, LPVOID)) { return 0; } else { - RCT2_GLOBAL(RCT2_ADDRESS_SOUND_INFO_LIST_MAPPING, LPVOID) = map_file(filename, 0, 0); - return RCT2_GLOBAL(RCT2_ADDRESS_SOUND_INFO_LIST_MAPPING, LPVOID) != 0; + RCT2_GLOBAL(RCT2_ADDRESS_SOUND_EFFECTS_MAPPING, LPVOID) = map_file(filename, 0, 0); + return RCT2_GLOBAL(RCT2_ADDRESS_SOUND_EFFECTS_MAPPING, LPVOID) != 0; } } @@ -447,7 +453,7 @@ int sub_4015E7(int channel) int zero = 0; rct_sound_channel* sound_channel = &RCT2_ADDRESS(0x014262E0, rct_sound_channel)[channel]; LPDIRECTSOUNDBUFFER dsbuffer = RCT2_ADDRESS(RCT2_ADDRESS_DSOUND_BUFFERS, LPDIRECTSOUNDBUFFER)[channel]; - int result = dsbuffer->lpVtbl->Lock(dsbuffer, 0, sound_channel->var_150, (LPVOID*)&buf1, (LPDWORD)&buf1size, (LPVOID*)&buf2, (LPDWORD)&buf2size, 0); + int result = dsbuffer->lpVtbl->Lock(dsbuffer, 0, sound_channel->bufsize, (LPVOID*)&buf1, (LPDWORD)&buf1size, (LPVOID*)&buf2, (LPDWORD)&buf2size, 0); if (SUCCEEDED(result)) { if (buf1size) { mmio_read(sound_channel->hmmio, buf1size, buf1, &sound_channel->mmckinfo1, &read); @@ -466,8 +472,8 @@ int sub_4015E7(int channel) } else { sound_channel->var_168 = 1; sound_channel->var_15C = read; - rct_audio_info* audio_info = sound_channel->hmem; - uint16 v = ((audio_info->var_E != 8) - 1) & 0x80; + LPWAVEFORMATEX waveformat = sound_channel->hmem; + uint16 v = ((waveformat->nBlockAlign != 8) - 1) & 0x80; memset(&buf1[read], v, buf1size - r); } } @@ -479,11 +485,26 @@ int sub_4015E7(int channel) return result; } +/** +* +* rct2: 0x00401AF3 +*/ +void sub_401AF3(int channel, const char* filename, int a3, int a4) +{ + rct_sound_channel* sound_channel = &RCT2_ADDRESS(RCT2_ADDRESS_SOUND_CHANNEL_LIST, rct_sound_channel)[channel]; + sound_channel->var_4 = 1; + memcpy(sound_channel->filename, filename, sizeof(sound_channel->filename)); + sound_channel->var_10C = 0; + sound_channel->var_110 = a4; + sound_channel->var_114 = a3; + sound_channel->var_164 = 1; +} + /** * * rct2: 0x004016FF */ -int sound_channel_load_file(int channel, char* filename, int offset) +int sound_channel_load_file(int channel, const char* filename, int offset) { rct_sound_channel* sound_channel = &RCT2_ADDRESS(0x014262E0, rct_sound_channel)[channel]; sound_channel->hmem; @@ -499,11 +520,11 @@ int sound_channel_load_file(int channel, char* filename, int offset) sound_channel_free(&sound_channel->hmmio, &sound_channel->hmem); return -103; } - sound_channel->var_150 = 120 * *((uint32*)sound_channel->hmem + 2) / 100; + sound_channel->bufsize = 120 * *((uint32*)sound_channel->hmem + 2) / 100; DSBUFFERDESC bufferdesc; memset(&bufferdesc, 0, sizeof(bufferdesc)); bufferdesc.dwFlags = RCT2_GLOBAL(0x009E1AA8, uint32) | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPAN | DSBCAPS_CTRLFREQUENCY; - bufferdesc.dwBufferBytes = sound_channel->var_150; + bufferdesc.dwBufferBytes = sound_channel->bufsize; bufferdesc.lpwfxFormat = sound_channel->hmem; bufferdesc.dwSize = sizeof(bufferdesc); int ret = RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND)->lpVtbl->CreateSoundBuffer(RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND), &bufferdesc, &RCT2_ADDRESS(RCT2_ADDRESS_DSOUND_BUFFERS, LPDIRECTSOUNDBUFFER)[channel], 0); @@ -524,18 +545,18 @@ int sound_channel_load_file(int channel, char* filename, int offset) * * rct2: 0x00405222 */ -MMRESULT mmio_open(char* filename, HMMIO* hmmio, HGLOBAL* hmem, LPMMCKINFO mmckinfo) +MMRESULT mmio_open(const char* filename, HMMIO* hmmio, HGLOBAL* hmem, LPMMCKINFO mmckinfo) { HGLOBAL* hmemold; HGLOBAL hmemold2; HMMIO hmmio1; MMRESULT result; MMCKINFO mmckinfo1; - rct_audio_info audio_info; + WAVEFORMATEX waveformat; hmemold = hmem; *hmem = 0; - hmmio1 = mmioOpenA(filename, 0, MMIO_ALLOCBUF); + hmmio1 = mmioOpenA((char*)filename, 0, MMIO_ALLOCBUF); if (hmmio1) { result = mmioDescend(hmmio1, mmckinfo, 0, 0); if (result != MMSYSERR_NOERROR) { @@ -555,20 +576,20 @@ MMRESULT mmio_open(char* filename, HMMIO* hmmio, HGLOBAL* hmem, LPMMCKINFO mmcki result = 57601; goto label20; } - if (mmioRead(hmmio1, (HPSTR)&audio_info, 16) == 16) { - if (audio_info.var_0 == 1) { + if (mmioRead(hmmio1, (HPSTR)&waveformat, 16) == 16) { + if (waveformat.wFormatTag == 1) { //strcpy(audio_info.var_0, "\x01"); hmem = 0; label11: - hmemold2 = GlobalAlloc(0, (uint16)hmem + 18); + hmemold2 = GlobalAlloc(0, (SIZE_T)(hmem + 18)); *hmemold = hmemold2; if (!hmemold2) { result = 57344; goto label20; } - memcpy(hmemold2, &audio_info, 16); + memcpy(hmemold2, &waveformat, 16); *((uint16*)*hmemold + 8) = (uint16)hmem; - if (!(uint16)hmem || mmioRead(hmmio1, (char*)*hmemold + 18, (uint16)hmem) == (uint16)hmem) { + if (!hmem || mmioRead(hmmio1, (char*)*hmemold + 18, (LONG)hmem) == (LONG)hmem) { result = mmioAscend(hmmio1, &mmckinfo1, 0); if (!result) { goto label24; @@ -698,10 +719,10 @@ void audio_timefunc(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, D if (dwCurrentPlayCursor >= sound_channel->playpos) { var1 = dwCurrentPlayCursor - sound_channel->playpos; } else { - var1 = dwCurrentPlayCursor + sound_channel->var_150 - sound_channel->playpos; + var1 = dwCurrentPlayCursor + sound_channel->bufsize - sound_channel->playpos; } if (bufferlost) { - var2 = 2 * sound_channel->var_150 / 6; + var2 = 2 * sound_channel->bufsize / 6; } else { var2 = var1; } @@ -726,8 +747,8 @@ void audio_timefunc(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, D } sound_channel->dsbuffer->lpVtbl->Unlock(sound_channel->dsbuffer, buf1, buf1size, buf2, buf2size); sound_channel->playpos += var2; - if (sound_channel->playpos >= sound_channel->var_150) { - sound_channel->playpos = sound_channel->playpos - sound_channel->var_150; + if (sound_channel->playpos >= sound_channel->bufsize) { + sound_channel->playpos = sound_channel->playpos - sound_channel->bufsize; } return; } @@ -768,7 +789,7 @@ void audio_timefunc(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, D if (dwCurrentPlayCursor <= sound_channel->playpos) { sound_channel->var_15C = sound_channel->playpos - dwCurrentPlayCursor; } else { - sound_channel->var_15C = sound_channel->playpos + sound_channel->var_150 - dwCurrentPlayCursor; + sound_channel->var_15C = sound_channel->playpos + sound_channel->bufsize - dwCurrentPlayCursor; } goto label49; } @@ -795,8 +816,8 @@ void audio_timefunc(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, D label68: sound_channel->dsbuffer->lpVtbl->Unlock(sound_channel->dsbuffer, buf1, buf1size, buf2, buf2size); sound_channel->playpos += var2; - if (sound_channel->playpos >= sound_channel->var_150) { - sound_channel->playpos -= sound_channel->var_150; + if (sound_channel->playpos >= sound_channel->bufsize) { + sound_channel->playpos -= sound_channel->bufsize; } if (bufferlost != 0) { sound_channel->dsbuffer->lpVtbl->Play(sound_channel->dsbuffer, 0, 0, DSBPLAY_LOOPING); @@ -830,7 +851,7 @@ void audio_timefunc(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, D if (dwCurrentPlayCursor <= sound_channel->playpos) { sound_channel->var_15C = sound_channel->playpos - dwCurrentPlayCursor; } else { - sound_channel->var_15C = sound_channel->playpos + sound_channel->var_150 - dwCurrentPlayCursor; + sound_channel->var_15C = sound_channel->playpos + sound_channel->bufsize - dwCurrentPlayCursor; } goto label68; } @@ -875,6 +896,48 @@ int audio_create_timer() return 1; } +/** +* +* rct2: 0x006BA8E0 +*/ +void audio_init1() +{ + int devicenum = 0; + if (RCT2_GLOBAL(0x009AAC5C, uint8)) { + rct_dsdevice* dsdevice = &RCT2_GLOBAL(RCT2_ADDRESS_DSOUND_DEVICES, rct_dsdevice*)[0]; + while (dsdevice->guid.Data1 != RCT2_GLOBAL(RCT2_ADDRESS_DSOUND_GUID, GUID).Data1 || + dsdevice->guid.Data2 != RCT2_GLOBAL(RCT2_ADDRESS_DSOUND_GUID, GUID).Data2 || + dsdevice->guid.Data3 != RCT2_GLOBAL(RCT2_ADDRESS_DSOUND_GUID, GUID).Data3 || + memcmp(dsdevice->guid.Data4, RCT2_GLOBAL(RCT2_ADDRESS_DSOUND_GUID, GUID).Data4, sizeof(dsdevice->guid.Data4)) != 0) { + dsdevice++; + devicenum++; + if (devicenum >= RCT2_GLOBAL(RCT2_ADDRESS_NUM_DSOUND_DEVICES, int)) { + devicenum = 0; + break; + } + } + } + audio_init2(devicenum); + int m = 0; + do { + rct_music_info3* music_info3 = &RCT2_GLOBAL(0x009AF1C8, rct_music_info3*)[m]; + const char* path = get_file_path(music_info3->pathid); + RCT2_GLOBAL(0x014241BC, uint32) = 3; + HANDLE hfile = osinterface_file_open(path); + RCT2_GLOBAL(0x014241BC, uint32) = 0; + if (hfile != INVALID_HANDLE_VALUE) { + RCT2_GLOBAL(0x014241BC, uint32) = 3; + osinterface_file_read(hfile, &RCT2_GLOBAL(0x009AF47E, uint32), 4); + osinterface_file_close(hfile); + RCT2_GLOBAL(0x014241BC, uint32) = 0; + if (RCT2_GLOBAL(0x009AF47E, uint32) == 0x78787878) { + music_info3->var_0 = 0; + } + } + m++; + } while(m + 1 < 0x2E); +} + /** * * rct2: 0x006BA9B5 @@ -882,8 +945,8 @@ int audio_create_timer() void audio_init2(int device) { audio_close(); - for (int i = 0; i < 7; i++) { - rct_vehicle_sound* vehicle_sound = &RCT2_ADDRESS(RCT2_ADDRESS_VEHICLE_SOUND_LIST, rct_vehicle_sound)[i]; + for (int i = 0; i < countof(gVehicleSoundList); i++) { + rct_vehicle_sound* vehicle_sound = &gVehicleSoundList[i];//&RCT2_ADDRESS(RCT2_ADDRESS_VEHICLE_SOUND_LIST, rct_vehicle_sound)[i]; vehicle_sound->id = 0xFFFF; } for (int i = 0; i < 7; i++) { @@ -898,7 +961,7 @@ void audio_init2(int device) } const char * filepath = get_file_path(2); RCT2_GLOBAL(0x014241BC, uint32) = 1; - int successmap = map_sound_info(filepath); + int successmap = map_sound_effects(filepath); RCT2_GLOBAL(0x014241BC, uint32) = 0; if (!successmap) { RCT2_GLOBAL(0x014241BC, uint32) = 1; @@ -908,20 +971,17 @@ void audio_init2(int device) } RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SOUND_DEVICE, uint32) = device; rct_dsdevice dsdevice = RCT2_GLOBAL(RCT2_ADDRESS_DSOUND_DEVICES, rct_dsdevice*)[device]; - RCT2_GLOBAL(0x009AAC5D, uint32) = dsdevice.guid.Data1; - RCT2_GLOBAL(0x009AAC61, uint32) = dsdevice.guid.Data2; - RCT2_GLOBAL(0x009AAC65, uint32) = dsdevice.guid.Data3; - RCT2_GLOBAL(0x009AAC69, uint32) = (uint32)dsdevice.guid.Data4; + RCT2_GLOBAL(RCT2_ADDRESS_DSOUND_GUID, GUID) = dsdevice.guid; RCT2_GLOBAL(0x009AAC5C, uint8) = 1; config_save(); RCT2_GLOBAL(0x014241BC, uint32) = 1; int successtimer = audio_create_timer(); RCT2_GLOBAL(0x014241BC, uint32) = 0; if (successtimer) { - if ((RCT2_GLOBAL(0x009AF284, uint32) & (1 << 0))) { - for (int i = 0; i < 2; i++) { - RCT2_GLOBAL(0x009AF46C + (i * 8), uint8) = -1; - } + RCT2_GLOBAL(0x009AF284, uint32) |= (1 << 0); + for (int i = 0; i < 2; i++) { + rct_music_info2* music_info2 = &RCT2_ADDRESS(0x009AF46C, rct_music_info2)[i]; + music_info2->id = -1; } } if (!(RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) & 1 << 4)) { @@ -1030,10 +1090,10 @@ rct_sound* sound_next(rct_sound* sound) * * rct2: 0x00405206 */ -rct_sound_info* sound_get_info(uint16 sound_id) +rct_sound_effect* sound_get_effect(uint16 sound_id) { - if (RCT2_GLOBAL(RCT2_ADDRESS_SOUND_INFO_LIST_MAPPING, LPVOID) && sound_id < RCT2_GLOBAL(RCT2_ADDRESS_SOUND_INFO_LIST_MAPPING, uint32*)[0]) { - return (rct_sound_info*)(RCT2_GLOBAL(RCT2_ADDRESS_SOUND_INFO_LIST_MAPPING, int) + RCT2_GLOBAL(RCT2_ADDRESS_SOUND_INFO_LIST_MAPPING, uint32*)[sound_id + 1]); + if (RCT2_GLOBAL(RCT2_ADDRESS_SOUND_EFFECTS_MAPPING, LPVOID) && sound_id < RCT2_GLOBAL(RCT2_ADDRESS_SOUND_EFFECTS_MAPPING, uint32*)[0]) { + return (rct_sound_effect*)(RCT2_GLOBAL(RCT2_ADDRESS_SOUND_EFFECTS_MAPPING, int) + RCT2_GLOBAL(RCT2_ADDRESS_SOUND_EFFECTS_MAPPING, uint32*)[sound_id + 1]); } return 0; } @@ -1042,11 +1102,11 @@ rct_sound_info* sound_get_info(uint16 sound_id) * * rct2: 0x00405054 */ -int sound_info_loadvars(rct_sound_info* sound_info, LPWAVEFORMATEX* waveformat, char** data, DWORD* buffersize) +int sound_effect_loadvars(rct_sound_effect* sound_effect, LPWAVEFORMATEX* waveformat, char** data, DWORD* buffersize) { - *buffersize = sound_info->size; - *waveformat = &sound_info->format; - *data = (char*)&sound_info->data; + *buffersize = sound_effect->size; + *waveformat = &sound_effect->format; + *data = (char*)&sound_effect->data; return 1; } @@ -1095,9 +1155,9 @@ int sound_prepare(int sound_id, rct_sound *sound, int channels, int software) return 1; } } - rct_sound_info* sound_info = sound_get_info(sound_id); - if (sound_info) { - if (sound_info_loadvars(sound_info, &bufferdesc.lpwfxFormat, &buffer, &bufferdesc.dwBufferBytes)) { + rct_sound_effect* sound_effect = sound_get_effect(sound_id); + if (sound_effect) { + if (sound_effect_loadvars(sound_effect, &bufferdesc.lpwfxFormat, &buffer, &bufferdesc.dwBufferBytes)) { bufferdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_STATIC; if (channels) { if (channels == 2) { @@ -1134,17 +1194,68 @@ int sound_prepare(int sound_id, rct_sound *sound, int channels, int software) /** * * rct2: 0x006BB76E +* +* @param sound_id (eax) +* @param ebx (ebx) +* @param x (cx) +* @param y (dx) +* @param z (bp) */ -int sound_play_panned(int sound_id, int x) +int sound_play_panned(int sound_id, int ebx, sint16 x, sint16 y, sint16 z) { - //RCT2_CALLPROC_X(0x006BB76E, sound_id, x, 0, 0, 0, 0, 0); - // this function is not complete, need to add in volume adjust int result = 0; if (RCT2_GLOBAL(0x009AF59D, uint8) & 1) { RCT2_GLOBAL(0x00F438AD, uint8) = 0; int volume = 0; - if (x == 0x8001) { - // stuff to adjust volume + if (ebx == 0x8001) { + sint16 x2 = x & 0xFFE0; // round by 32 + sint16 y2 = y & 0xFFE0; + if (x2 < 0x1FFF && y2 < 0x1FFF) { + rct_map_element* mapelement = RCT2_ADDRESS(RCT2_ADDRESS_TILE_MAP_ELEMENT_POINTERS, rct_map_element*)[((y2 * 256 + x2) & 0xFFFF) / 8]; + while (mapelement->type & MAP_ELEMENT_TYPE_MASK) { + mapelement++; + } + if ((mapelement->base_height * 8) - 5 > z) { + RCT2_GLOBAL(0x00F438AD, uint8) = 10; + } + } + sint16 v11; + sint16 v12; + switch (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32)) { + case 0: + v11 = y - x; + v12 = ((y + x) / 2) - z; + break; + case 1: + v11 = -x - y; + v12 = ((y - x) / 2) - z; + break; + case 2: + v11 = x - y; + v12 = ((-y - x) / 2) - z; + break; + case 3: + v11 = y + x; + v12 = ((x - y) / 2) - z; + break; + } + rct_window* window = RCT2_GLOBAL(RCT2_ADDRESS_NEW_WINDOW_PTR, rct_window*); + while (1) { + window--; + if (window < RCT2_ADDRESS(RCT2_ADDRESS_WINDOW_LIST, rct_window)) { + break; + } + rct_viewport* viewport = window->viewport; + if (viewport && viewport->flags & VIEWPORT_FLAG_SOUND_ON) { + sint16 v15 = v12 - viewport->view_y; + sint16 v16 = v11 - viewport->view_x; + ebx = viewport->x + (v16 >> viewport->zoom); + volume = RCT2_ADDRESS(0x0099282C, int)[sound_id] + ((-1024 * viewport->zoom - 1) << RCT2_GLOBAL(0x00F438AD, uint8)) + 1; + if (v15 < 0 || v15 >= viewport->view_height || v16 < 0 || v16 >= viewport->view_width || volume < -10000) { + return sound_id; + } + } + } } int i = 0; rct_other_sound* other_sound = &RCT2_ADDRESS(0x009AF484, rct_other_sound)[i]; @@ -1157,10 +1268,10 @@ int sound_play_panned(int sound_id, int x) } other_sound->id = sound_id; int pan; - if (x == 0x8000) { + if (ebx == 0x8000) { pan = 0; } else { - int x2 = x << 16; + int x2 = ebx << 16; uint16 screenwidth = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16); if (screenwidth < 64) { screenwidth = 64; @@ -1170,13 +1281,16 @@ int sound_play_panned(int sound_id, int x) if (!RCT2_GLOBAL(0x009AAC6D, uint8)) { pan = 0; } - +#ifdef USE_MIXER + Mixer_Play_Effect(sound_id, MIXER_LOOP_NONE, DStoMixerVolume(volume), DStoMixerPan(pan), 1, 1); +#else RCT2_GLOBAL(0x014241BC, uint32) = 1; sound_prepare(sound_id, &other_sound->sound, 1, RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_SOUND_SW_BUFFER, uint32)); RCT2_GLOBAL(0x014241BC, uint32) = 0; RCT2_GLOBAL(0x014241BC, uint32) = 1; result = sound_play(&other_sound->sound, 0, volume, pan, 0); RCT2_GLOBAL(0x014241BC, uint32) = 0; +#endif } return result; } @@ -1198,7 +1312,7 @@ int sub_401B63(int channel) * * rct2: 0x0040194E */ -int sound_channel_load_file2(int channel, char* filename, int offset) +int sound_channel_load_file2(int channel, const char* filename, int offset) { if (!RCT2_GLOBAL(0x009E1AA4, int)) { return 0; @@ -1221,6 +1335,9 @@ void start_title_music() { if ((RCT2_GLOBAL(0x009AF284, uint32) & (1 << 0)) && RCT2_GLOBAL(0x009AF59D, uint8) & 1 && RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 1) { if (!RCT2_GLOBAL(0x009AF600, uint8)) { +#ifdef USE_MIXER + gMusicChannels[3] = Mixer_Play_Music(PATH_ID_CSS17); +#else RCT2_GLOBAL(0x014241BC, uint32) = 1; int result = sound_channel_load_file2(3, (char*)get_file_path(PATH_ID_CSS17), 0); RCT2_GLOBAL(0x014241BC, uint32) = 0; @@ -1229,6 +1346,7 @@ void start_title_music() sound_channel_play(3, 1, 0, 0, 0); RCT2_GLOBAL(0x014241BC, uint32) = 0; } +#endif RCT2_GLOBAL(0x009AF600, uint8) = 1; } } else { @@ -1496,7 +1614,7 @@ void pause_sounds() stop_other_sounds(); stop_vehicle_sounds(); stop_ride_music(); - stop_peep_sounds(); + stop_crowd_sound(); } g_sounds_disabled = 1; } @@ -1536,18 +1654,26 @@ void stop_other_sounds() void stop_vehicle_sounds() { if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SOUND_DEVICE, sint32) != -1) { - for (int i = 0; i < 7; i++) { - rct_vehicle_sound* vehicle_sound = &RCT2_ADDRESS(RCT2_ADDRESS_VEHICLE_SOUND_LIST, rct_vehicle_sound)[i]; + for (int i = 0; i < countof(gVehicleSoundList); i++) { + rct_vehicle_sound* vehicle_sound = &gVehicleSoundList[i];//&RCT2_ADDRESS(RCT2_ADDRESS_VEHICLE_SOUND_LIST, rct_vehicle_sound)[i]; if (vehicle_sound->id != 0xFFFF) { - if (vehicle_sound->var_18 != 0xFFFF) { + if (vehicle_sound->sound1_id != 0xFFFF) { +#ifdef USE_MIXER + Mixer_Stop_Channel(vehicle_sound->sound1_channel); +#else RCT2_GLOBAL(0x014241BC, uint32) = 1; sound_stop(&vehicle_sound->sound1); RCT2_GLOBAL(0x014241BC, uint32) = 0; +#endif } - if (vehicle_sound->var_34 != 0xFFFF) { + if (vehicle_sound->sound2_id != 0xFFFF) { +#ifdef USE_MIXER + Mixer_Stop_Channel(vehicle_sound->sound2_channel); +#else RCT2_GLOBAL(0x014241BC, uint32) = 1; sound_stop(&vehicle_sound->sound2); RCT2_GLOBAL(0x014241BC, uint32) = 0; +#endif } } vehicle_sound->id = 0xFFFF; @@ -1563,12 +1689,12 @@ void stop_ride_music() { if ((RCT2_GLOBAL(0x009AF284, uint32) & (1 << 0))) { for (int i = 0; i < 2; i++) { - uint8 * data = RCT2_ADDRESS(0x009AF46C + (i * 8), uint8); - if (data[0] != 0xFF) { + rct_music_info2* music_info2 = &RCT2_ADDRESS(0x009AF46C, rct_music_info2)[i]; + if (music_info2->id != (uint8)-1) { RCT2_GLOBAL(0x014241BC, uint32) = 1; sound_channel_stop(i); RCT2_GLOBAL(0x014241BC, uint32) = 0; - data[0] = 0xFF; + music_info2->id = -1; } } } @@ -1578,13 +1704,20 @@ void stop_ride_music() * * rct2: 0x006BD07F */ -void stop_peep_sounds() +void stop_crowd_sound() { if ((RCT2_GLOBAL(0x009AF284, uint32) & (1 << 0))) { if (RCT2_GLOBAL(0x009AF5FC, uint32) != 1) { +#ifdef USE_MIXER + if (gMusicChannels[2]) { + Mixer_Stop_Channel(gMusicChannels[2]); + gMusicChannels[2] = 0; + } +#else RCT2_GLOBAL(0x014241BC, uint32) = 1; sound_channel_stop(2); RCT2_GLOBAL(0x014241BC, uint32) = 0; +#endif RCT2_GLOBAL(0x009AF5FC, uint32) = 1; } } @@ -1598,9 +1731,16 @@ void stop_title_music() { if (RCT2_GLOBAL(0x009AF284, uint32) & (1 << 0)) { if (RCT2_GLOBAL(0x009AF600, uint8) != 0) { +#ifdef USE_MIXER + if (gMusicChannels[3]) { + Mixer_Stop_Channel(gMusicChannels[3]); + gMusicChannels[3] = 0; + } +#else RCT2_GLOBAL(0x014241BC, uint32) = 1; sound_channel_stop(3); RCT2_GLOBAL(0x014241BC, uint32) = 0; +#endif } } RCT2_GLOBAL(0x009AF600, uint8) = 0; @@ -1640,4 +1780,196 @@ void unpause_sounds() { RCT2_GLOBAL(0x009AF59C, uint8)--; g_sounds_disabled = 0; -} \ No newline at end of file +} + +/** +* Update zoom based volume attenuation for ride music +* rct2: 0x006BC348 +*/ +void sub_6BC348() +{ + RCT2_GLOBAL(0x009AF42C, void*) = &RCT2_GLOBAL(0x009AF430, void*); + RCT2_GLOBAL(0x00F438A4, rct_viewport*) = (rct_viewport*)-1; + rct_window* window = RCT2_GLOBAL(RCT2_ADDRESS_NEW_WINDOW_PTR, rct_window*); + while (1) { + window--; + if (window < RCT2_ADDRESS(RCT2_ADDRESS_WINDOW_LIST, rct_window)) { + break; + } + if (window->viewport && window->viewport->flags & VIEWPORT_FLAG_SOUND_ON) { + RCT2_GLOBAL(0x00F438A4, rct_viewport*) = window->viewport; + RCT2_GLOBAL(0x00F438A8, rct_window*) = window; + RCT2_GLOBAL(RCT2_ADDRESS_VOLUME_ADJUST_ZOOM, uint8) = 0; + if (window->viewport->zoom) { + RCT2_GLOBAL(RCT2_ADDRESS_VOLUME_ADJUST_ZOOM, uint8) = 30; + if (window->viewport->zoom != 1) { + RCT2_GLOBAL(RCT2_ADDRESS_VOLUME_ADJUST_ZOOM, uint8) = 60; + } + } + return; + } + } +} + +/** +* Play/update ride music based on structs updated somewhere else +* rct2: 0x006BC6D8 +*/ +void sub_6BC6D8() +{ + rct_music_info* edi; + int ebx; + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 2)) { + if ((RCT2_GLOBAL(0x009AF284, uint32) & (1 << 0))) { + if (!RCT2_GLOBAL(0x009AF59C, uint8) && RCT2_GLOBAL(0x009AF59D, uint8) & 1 && RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_MUSIC, uint8) && !(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 1)) { + while (1) { + int v8 = 0; + int v9 = 1; + rct_music_info* music_info = &RCT2_GLOBAL(0x009AF430, rct_music_info); + while (music_info < RCT2_GLOBAL(0x009AF42C, rct_music_info*)) { + if (music_info->id != (uint8)-1) { + rct_music_info3* music_info3 = &RCT2_GLOBAL(0x009AF1C8, rct_music_info3*)[music_info->var_1] + 8; + if (RCT2_ADDRESS(0x009AA0B1, uint8*)[music_info3->var_0]) { + v8++; + if (v9 >= music_info->volume) { + v9 = music_info->volume; + edi = music_info; + } + } + } + music_info++; + } + if (v8 <= 1) { + break; + } + edi->id = -1; + } + + while (1) { + int v8 = 0; + int v9 = 1; + rct_music_info* music_info = &RCT2_GLOBAL(0x009AF430, rct_music_info); + while (music_info < RCT2_GLOBAL(0x009AF42C, rct_music_info*)) { + if (music_info->id != (uint8)-1) { + v8++; + if (v9 >= music_info->volume) { + v9 = music_info->volume; + edi = music_info; + } + } + music_info++; + } + if (v8 <= 2) { + break; + } + edi->id = -1; + } + rct_music_info2* music_info2 = &RCT2_GLOBAL(0x009AF46C, rct_music_info2); + int channel = 0; + do { + if (music_info2->id != (uint8)-1) { + rct_music_info* music_info = &RCT2_GLOBAL(0x009AF430, rct_music_info); + while (music_info < RCT2_GLOBAL(0x009AF42C, rct_music_info*)) { + if (music_info->id == music_info2->id && music_info->var_1 == music_info2->var_1) { + RCT2_GLOBAL(0x014241BC, uint32) = 1; + int v16 = sub_401B63(channel); + RCT2_GLOBAL(0x014241BC, uint32) = 0; + if (v16) { + goto label32; + } + break; + } + music_info++; + } + RCT2_GLOBAL(0x014241BC, uint32) = 1; + sound_channel_stop(channel); + RCT2_GLOBAL(0x014241BC, uint32) = 0; + music_info2->id = -1; + } + label32: + music_info2++; + channel++; + } while(channel < 2); + + for (rct_music_info* music_info = &RCT2_GLOBAL(0x009AF430, rct_music_info); music_info < RCT2_GLOBAL(0x009AF42C, rct_music_info*); music_info++) { + if (music_info->id != (uint8)-1) { + rct_music_info2* music_info2 = &RCT2_GLOBAL(0x009AF46C, rct_music_info2); + int channel = 0; + while (music_info->id != music_info2->id || music_info->var_1 != music_info2->var_1) { + if (music_info2->id == (uint8)-1) { + ebx = channel; + } + music_info2++; + channel++; + if (channel >= 2) { + rct_music_info3* music_info3 = &RCT2_GLOBAL(0x009AF1C8, rct_music_info3*)[music_info->var_1]; + const char* filename = get_file_path(music_info3->pathid); + RCT2_GLOBAL(0x014241BC, uint32) = 3; + HANDLE hfile = osinterface_file_open(filename); + RCT2_GLOBAL(0x014241BC, uint32) = 0; + if (hfile != INVALID_HANDLE_VALUE) { + RCT2_GLOBAL(0x014241BC, uint32) = 3; + osinterface_file_read(hfile, &RCT2_GLOBAL(0x009AF47E, uint32), 4); + RCT2_GLOBAL(0x014241BC, uint32) = 3; + osinterface_file_close(hfile); + RCT2_GLOBAL(0x014241BC, uint32) = 0; + } + if (hfile == INVALID_HANDLE_VALUE || RCT2_GLOBAL(0x009AF47E, uint32) != 0x78787878) { + int offset = music_info->offset - 10000; + if (offset < 0) { + offset = 0; + } + RCT2_GLOBAL(0x014241BC, uint32) = 1; + int musicloaded = sound_channel_load_file2(ebx, filename, offset & 0xFFFFFFF0); + RCT2_GLOBAL(0x014241BC, uint32) = 0; + if (musicloaded) { + RCT2_GLOBAL(0x014241BC, uint32) = 1; + int musicplayed = sound_channel_play(ebx, 0, music_info->volume, music_info->pan, music_info->freq); + RCT2_GLOBAL(0x014241BC, uint32) = 0; + if (musicplayed) { + rct_music_info3* music_info3 = &RCT2_GLOBAL(0x009AF1C8, rct_music_info3*)[music_info->var_1]; + if (music_info3->var_9) { + RCT2_GLOBAL(0x014241BC, uint32) = 1; + sub_401AF3(ebx, get_file_path(music_info3->pathid), 1, 0); + RCT2_GLOBAL(0x014241BC, uint32) = 0; + } + rct_music_info2* music_info2 = &RCT2_ADDRESS(0x009AF46C, rct_music_info2)[ebx]; + music_info2->volume = music_info->volume; + music_info2->pan = music_info->pan; + music_info2->freq = music_info->freq; + music_info2->id = music_info->id; + music_info2->var_1 = music_info->var_1; + } + } else { + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_MUSIC, uint8) = 0; + } + } + return; + } + } + + if (music_info->volume != music_info2->volume) { + music_info2->volume = music_info->volume; + RCT2_GLOBAL(0x014241BC, uint32) = 1; + sound_channel_set_volume(channel, music_info->volume); + RCT2_GLOBAL(0x014241BC, uint32) = 0; + } + if (music_info->pan != music_info2->pan) { + music_info2->pan = music_info->pan; + RCT2_GLOBAL(0x014241BC, uint32) = 1; + sound_channel_set_pan(channel, music_info->pan); + RCT2_GLOBAL(0x014241BC, uint32) = 0; + } + if (music_info->freq != music_info2->freq) { + music_info2->freq = music_info->freq; + RCT2_GLOBAL(0x014241BC, uint32) = 1; + sound_channel_set_frequency(channel, music_info->freq); + RCT2_GLOBAL(0x014241BC, uint32) = 0; + } + + } + } + } + } + } +} diff --git a/src/audio.h b/src/audio/audio.h similarity index 76% rename from src/audio.h rename to src/audio/audio.h index c68b059e96..350b922a7e 100644 --- a/src/audio.h +++ b/src/audio/audio.h @@ -21,8 +21,8 @@ #ifndef _AUDIO_H_ #define _AUDIO_H_ -#include "rct2.h" -#include "sprite.h" +#include "../common.h" +#include "../world/sprite.h" typedef struct { char name[256]; @@ -31,9 +31,12 @@ typedef struct { extern int gAudioDeviceCount; extern audio_device *gAudioDevices; +#define AUDIO_MAX_VEHICLE_SOUNDS 14 + void audio_init(); void audio_quit(); void audio_get_devices(); +void audio_init1(); void audio_init2(int device); #include @@ -59,20 +62,11 @@ typedef struct rct_sound { struct rct_sound* next; } rct_sound; -typedef struct { - uint16 var_0; - uint16 channels; - uint32 samples; - uint32 var_8; - uint16 bytes; - uint16 bits; - uint16 var_E; -} rct_audio_info; - typedef struct { uint32 var_0; uint32 var_4; - char filename[0x108]; // 0x8 + char filename[MAX_PATH]; // 0x8 + uint32 var_10C; uint32 var_110; uint32 var_114; uint32 var_118; @@ -81,7 +75,7 @@ typedef struct { MMCKINFO mmckinfo1; // 0x124 MMCKINFO mmckinfo2; // 0x138 LPDIRECTSOUNDBUFFER dsbuffer; // 0x14C - uint32 var_150; + uint32 bufsize; uint32 playpos; // 0x154 uint32 var_158; uint32 var_15C; @@ -93,39 +87,69 @@ typedef struct { typedef struct { uint32 size; WAVEFORMATEX format; - char* data; -} rct_sound_info; + uint8* data; +} rct_sound_effect; typedef struct { uint16 id; uint16 var_2; rct_sound sound1; // 0x04 - uint16 var_18; - uint16 var_1A; - uint16 var_1C; - uint16 var_1D; + uint16 sound1_id; // 0x18 + sint16 sound1_volume; // 0x1A + sint16 sound1_pan; // 0x1C + uint16 sound1_freq; rct_sound sound2; // 0x20 - uint16 var_34; - uint16 pad_36; - uint16 var_38; - uint16 var_3A; + uint16 sound2_id; // 0x34 + sint16 sound2_volume; // 0x36 + sint16 sound2_pan; // 0x38 + uint16 sound2_freq; // 0x3A + + void* sound1_channel; + void* sound2_channel; } rct_vehicle_sound; +typedef struct { + uint16 id; + sint16 pan; // 0x2 + sint16 var_4; + uint16 frequency; // 0x6 + sint16 var_8; + uint16 var_A; // 0xA +} rct_vehicle_sound_params; + typedef struct { uint16 id; rct_sound sound; } rct_other_sound; typedef struct { - uint16 id; - uint8 var_2; - uint8 var_3; - uint8 var_4; - uint16 var_5; - uint8 var_7; - uint16 var_8; - uint16 next; // 0xA -} rct_sound_unknown; + uint8 id; + uint8 var_1; + sint32 offset; //0x2 + sint16 volume; //0x6 + sint16 pan; //0x8 + uint16 freq; //0xA +} rct_music_info; + +typedef struct { + uint8 id; + uint8 var_1; + uint16 volume; //0x2 + uint16 pan; //0x4 + uint16 freq; //0x6 +} rct_music_info2; + +typedef struct { + uint8 var_0; + uint8 pad_1[0x7]; + uint8 pathid; //0x8 + uint8 var_9; +} rct_music_info3; + +extern rct_vehicle_sound gVehicleSoundList[AUDIO_MAX_VEHICLE_SOUNDS]; +extern rct_vehicle_sound_params gVehicleSoundParamsList[AUDIO_MAX_VEHICLE_SOUNDS]; +extern rct_vehicle_sound_params *gVehicleSoundParamsListEnd; +extern void* gMusicChannels[4]; int get_dsound_devices(); int dsound_create_primary_buffer(int a, int device, int channels, int samples, int bits); @@ -133,15 +157,18 @@ void audio_timefunc(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, D int audio_release(); MMRESULT mmio_read(HMMIO hmmio, uint32 size, char* buffer, LPMMCKINFO mmckinfo, int* read); MMRESULT mmio_seek(HMMIO* hmmio, LPMMCKINFO mmckinfo1, LPMMCKINFO mmckinfo2, int offset); -MMRESULT mmio_open(char* filename, HMMIO* hmmio, HGLOBAL* hmem, LPMMCKINFO mmckinfo); +MMRESULT mmio_open(const char* filename, HMMIO* hmmio, HGLOBAL* hmem, LPMMCKINFO mmckinfo); int sub_40153B(int channel); int sub_4015E7(int channel); +void sub_401AF3(int channel, const char* filename, int a3, int a4); +int sub_401B63(int channel); +void sub_6BC6D8(); int audio_remove_timer(); void audio_close(); LPVOID map_file(LPCSTR lpFileName, DWORD dwCreationDisposition, DWORD dwNumberOfBytesToMap); -int unmap_sound_info(); +int unmap_sound_effects(); int sound_prepare(int sound_id, rct_sound *sound, int channels, int software); -int sound_play_panned(int sound_id, int x); +int sound_play_panned(int sound_id, int ebx, sint16 x, sint16 y, sint16 z); int sound_play(rct_sound* sound, int looping, int volume, int pan, int frequency); int sound_is_playing(rct_sound* sound); int sound_set_frequency(rct_sound* sound, int frequency); @@ -151,8 +178,8 @@ int sound_channel_play(int channel, int a2, int volume, int pan, int frequency); int sound_channel_set_frequency(int channel, int frequency); int sound_channel_set_pan(int channel, int pan); int sound_channel_set_volume(int channel, int volume); -int sound_channel_load_file2(int channel, char* filename, int offset); -int sound_channel_load_file(int channel, char* filename, int offset); +int sound_channel_load_file2(int channel, const char* filename, int offset); +int sound_channel_load_file(int channel, const char* filename, int offset); void sound_channel_free(HMMIO* hmmio, HGLOBAL* hmem); int sound_stop(rct_sound *sound); int sound_stop_all(); @@ -167,7 +194,7 @@ void stop_completed_sounds(); void stop_other_sounds(); void stop_vehicle_sounds(); void stop_ride_music(); -void stop_peep_sounds(); +void stop_crowd_sound(); void stop_title_music(); void start_title_music(); void unpause_sounds(); @@ -239,7 +266,8 @@ typedef enum { SOUND_TRAM = 59, SOUND_DOOR_OPEN = 60, SOUND_DOOR_CLOSE = 61, - SOUND_62 = 62 + SOUND_62 = 62, + SOUND_MAXID } RCT2_SOUND; #endif diff --git a/src/audio/mixer.cpp b/src/audio/mixer.cpp new file mode 100644 index 0000000000..f71c7bda8e --- /dev/null +++ b/src/audio/mixer.cpp @@ -0,0 +1,572 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of OpenRCT2. + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#include +#include +#include + +extern "C" { +#include "../config.h" +#include "audio.h" +} +#include "mixer.h" + +Mixer gMixer; + +Sample::Sample() +{ + data = 0; + length = 0; + issdlwav = false; +} + +Sample::~Sample() +{ + Unload(); +} + +bool Sample::Load(const char* filename) +{ + Unload(); + SDL_RWops* rw = SDL_RWFromFile(filename, "rb"); + if (!rw) { + SDL_RWclose(rw); + return false; + } + SDL_AudioSpec audiospec; + memset(&audiospec, 0, sizeof(audiospec)); + SDL_AudioSpec* spec = SDL_LoadWAV_RW(rw, false, &audiospec, &data, (Uint32*)&length); + if (spec != NULL) { + format.freq = spec->freq; + format.format = spec->format; + format.channels = spec->channels; + issdlwav = true; + } else { + return false; + } + return true; +} + +bool Sample::LoadCSS1(const char* filename, unsigned int offset) +{ + Unload(); + SDL_RWops* rw = SDL_RWFromFile(filename, "rb"); + if (!rw) { + return false; + } + Uint32 numsounds; + SDL_RWread(rw, &numsounds, sizeof(numsounds), 1); + if (offset > numsounds) { + SDL_RWclose(rw); + return false; + } + SDL_RWseek(rw, offset * 4, RW_SEEK_CUR); + Uint32 soundoffset; + SDL_RWread(rw, &soundoffset, sizeof(soundoffset), 1); + SDL_RWseek(rw, soundoffset, RW_SEEK_SET); + Uint32 soundsize; + SDL_RWread(rw, &soundsize, sizeof(soundsize), 1); + length = soundsize; + WAVEFORMATEX waveformat; + SDL_RWread(rw, &waveformat, sizeof(waveformat), 1); + format.freq = waveformat.nSamplesPerSec; + format.format = AUDIO_S16LSB; + format.channels = waveformat.nChannels; + data = new uint8[length]; + SDL_RWread(rw, data, length, 1); + SDL_RWclose(rw); + return true; +} + +void Sample::Unload() +{ + if (data) { + if (issdlwav) { + SDL_FreeWAV(data); + } else { + delete[] data; + } + data = 0; + } + issdlwav = false; + length = 0; +} + +bool Sample::Loaded() +{ + return data != 0; +} + +bool Sample::Convert(AudioFormat format) +{ + if(Sample::format.format != format.format || Sample::format.channels != format.channels || Sample::format.freq != format.freq){ + SDL_AudioCVT cvt; + if (SDL_BuildAudioCVT(&cvt, Sample::format.format, Sample::format.channels, Sample::format.freq, format.format, format.channels, format.freq) < 0) { + return false; + } + cvt.len = length; + cvt.buf = (Uint8*)new uint8[cvt.len * cvt.len_mult]; + memcpy(cvt.buf, data, length); + if (SDL_ConvertAudio(&cvt) < 0) { + delete[] cvt.buf; + return false; + } + Unload(); + data = cvt.buf; + length = cvt.len_cvt; + Sample::format = format; + return true; + } + return false; +} + +const uint8* Sample::Data() +{ + return data; +} + +unsigned long Sample::Length() +{ + return length; +} + +Stream::Stream() +{ + sourcetype = SOURCE_NONE; +} + +unsigned long Stream::GetSome(unsigned long offset, const uint8** data, unsigned long length) +{ + unsigned long size = length; + switch(sourcetype) { + case SOURCE_SAMPLE: + if (offset >= sample->Length()) { + return 0; + } + if (offset + length > sample->Length()) { + size = sample->Length() - offset; + } + *data = &sample->Data()[offset]; + return size; + break; + } + return 0; +} + +unsigned long Stream::Length() +{ + switch(sourcetype) { + case SOURCE_SAMPLE: + return sample->Length(); + break; + } + return 0; +} + +void Stream::SetSource_Sample(Sample& sample) +{ + sourcetype = SOURCE_SAMPLE; + Stream::sample = &sample; +} + +const AudioFormat* Stream::Format() +{ + switch(sourcetype) { + case SOURCE_SAMPLE: + return &sample->format; + break; + } + return 0; +} + +Channel::Channel() +{ + resampler = 0; + SetRate(1); + SetVolume(SDL_MIX_MAXVOLUME); + SetPan(0.5f); + done = true; +} + +Channel::~Channel() +{ + if (resampler) { + speex_resampler_destroy(resampler); + resampler = 0; + } +} + +void Channel::Play(Stream& stream, int loop = MIXER_LOOP_NONE) +{ + Channel::stream = &stream; + Channel::loop = loop; + offset = 0; + done = false; +} + +void Channel::SetRate(double rate) +{ + Channel::rate = rate; + if (Channel::rate < 0.001) { + Channel::rate = 0.001; + } +} + +void Channel::SetVolume(int volume) +{ + Channel::volume = volume; + if (volume > SDL_MIX_MAXVOLUME) { + Channel::volume = SDL_MIX_MAXVOLUME; + } + if (volume < 0) { + Channel::volume = 0; + } +} + +void Channel::SetPan(float pan) +{ + Channel::pan = pan; + if (pan > 1) { + Channel::pan = 1; + } + if (pan < 0) { + Channel::pan = 0; + } + volume_l = (float)sin((1.0 - Channel::pan) * M_PI / 2.0); + volume_r = (float)sin(Channel::pan * M_PI / 2.0); +} + +bool Channel::IsPlaying() +{ + return !done; +} + +void Mixer::Init(const char* device) +{ + Close(); + SDL_AudioSpec want, have; + SDL_zero(want); + want.freq = 44100; + want.format = AUDIO_S16SYS; + want.channels = 2; + want.samples = 1024; + want.callback = Callback; + want.userdata = this; + deviceid = SDL_OpenAudioDevice(device, 0, &want, &have, 0); + format.format = have.format; + format.channels = have.channels; + format.freq = have.freq; + const char* filename = get_file_path(PATH_ID_CSS1); + for (int i = 0; i < SOUND_MAXID; i++) { + css1samples[i].LoadCSS1(filename, i); + css1samples[i].Convert(format); // convert to audio output format, saves some cpu usage but requires a bit more memory, optional + css1streams[i].SetSource_Sample(css1samples[i]); + } + effectbuffer = new uint8[(have.samples * format.BytesPerSample() * format.channels) + 200]; + SDL_PauseAudioDevice(deviceid, 0); +} + +void Mixer::Close() +{ + Lock(); + while (channels.begin() != channels.end()) { + Stop(*(*channels.begin())); + } + Unlock(); + SDL_CloseAudioDevice(deviceid); + delete[] effectbuffer; +} + +void Mixer::Lock() +{ + SDL_LockAudioDevice(deviceid); +} + +void Mixer::Unlock() +{ + SDL_UnlockAudioDevice(deviceid); +} + +Channel* Mixer::Play(Stream& stream, int loop, bool deleteondone) +{ + Lock(); + Channel* newchannel = new (std::nothrow) Channel(); + if (newchannel) { + newchannel->Play(stream, loop); + newchannel->deleteondone = deleteondone; + channels.push_back(newchannel); + } + Unlock(); + return newchannel; +} + +void Mixer::Stop(Channel& channel) +{ + Lock(); + channels.remove(&channel); + delete &channel; + Unlock(); +} + +bool Mixer::LoadMusic(int pathid) +{ + if (pathid >= PATH_ID_END) { + return false; + } + if (!musicsamples[pathid].Loaded()) { + const char* filename = get_file_path(pathid); + musicstreams[pathid].SetSource_Sample(musicsamples[pathid]); + return musicsamples[pathid].Load(filename); + } else { + return true; + } +} + +void SDLCALL Mixer::Callback(void* arg, uint8* stream, int length) +{ + Mixer* mixer = (Mixer*)arg; + memset(stream, 0, length); + std::list::iterator i = mixer->channels.begin(); + while (i != mixer->channels.end()) { + mixer->MixChannel(*(*i), stream, length); + if ((*i)->done && (*i)->deleteondone) { + delete (*i); + i = mixer->channels.erase(i); + } else { + i++; + } + } +} + +void Mixer::MixChannel(Channel& channel, uint8* data, int length) +{ + if (channel.stream && !channel.done) { + if (!channel.resampler) { + channel.resampler = speex_resampler_init(format.channels, format.freq, format.freq, 0, 0); + } + AudioFormat channelformat = *channel.stream->Format(); + int loaded = 0; + SDL_AudioCVT cvt; + cvt.len_ratio = 1; + do { + int samplesize = format.channels * format.BytesPerSample(); + int samples = length / samplesize; + int samplesloaded = loaded / samplesize; + double rate = 1; + if (format.format == AUDIO_S16SYS) { + rate = channel.rate; + } + int samplestoread = (int)ceil((samples - samplesloaded) * rate); + int lengthloaded = 0; + if (channel.offset < channel.stream->Length()) { + bool mustconvert = false; + if (MustConvert(*channel.stream)) { + if (SDL_BuildAudioCVT(&cvt, channelformat.format, channelformat.channels, channelformat.freq, Mixer::format.format, Mixer::format.channels, Mixer::format.freq) == -1) { + break; + } + mustconvert = true; + } + + const uint8* datastream = 0; + int readfromstream = (channel.stream->GetSome(channel.offset, &datastream, (int)(((samplestoread) * samplesize) / cvt.len_ratio)) / channelformat.BytesPerSample()) * channelformat.BytesPerSample(); + if (readfromstream == 0) { + break; + } + + int volume = channel.volume; + uint8* dataconverted = 0; + const uint8* tomix = 0; + + if (mustconvert) { + if (Convert(cvt, datastream, readfromstream, &dataconverted)) { + tomix = dataconverted; + lengthloaded = (cvt.len_cvt / samplesize) * samplesize; + } else { + break; + } + } else { + tomix = datastream; + lengthloaded = readfromstream; + } + + bool effectbufferloaded = false; + if (rate != 1 && format.format == AUDIO_S16SYS) { + int in_len = (int)(ceil((double)lengthloaded / samplesize)); + int out_len = samples + 20; // needs some extra, otherwise resampler sometimes doesn't process all the input samples + speex_resampler_set_rate(channel.resampler, format.freq, (int)(format.freq * (1 / rate))); + speex_resampler_process_interleaved_int(channel.resampler, (const spx_int16_t*)tomix, (spx_uint32_t*)&in_len, (spx_int16_t*)effectbuffer, (spx_uint32_t*)&out_len); + effectbufferloaded = true; + tomix = effectbuffer; + lengthloaded = (out_len * samplesize); + } + + if (channel.pan != 0.5f && format.channels == 2) { + if (!effectbufferloaded) { + memcpy(effectbuffer, tomix, lengthloaded); + effectbufferloaded = true; + tomix = effectbuffer; + } + switch (format.format) { + case AUDIO_S16SYS: + EffectPanS16(channel, (sint16*)effectbuffer, lengthloaded / samplesize); + break; + case AUDIO_U8: + EffectPanU8(channel, (uint8*)effectbuffer, lengthloaded / samplesize); + break; + } + } + + int mixlength = lengthloaded; + if (loaded + mixlength > length) { + mixlength = length - loaded; + } + + SDL_MixAudioFormat(&data[loaded], tomix, format.format, mixlength, volume); + + if (dataconverted) { + delete[] dataconverted; + } + + channel.offset += readfromstream; + + } + + loaded += lengthloaded; + + if (channel.loop != 0 && channel.offset >= channel.stream->Length()) { + if (channel.loop != -1) { + channel.loop--; + } + channel.offset = 0; + } + } while(loaded < length && channel.loop != 0); + if (channel.loop == 0 && channel.offset >= channel.stream->Length()) { + channel.done = true; + } + } +} + +void Mixer::EffectPanS16(Channel& channel, sint16* data, int length) +{ + float left = channel.volume_l; + float right = channel.volume_r; + for (int i = 0; i < length * 2; i += 2) { + data[i] = (sint16)(data[i] * left); + data[i + 1] = (sint16)(data[i + 1] * right); + } +} + +void Mixer::EffectPanU8(Channel& channel, uint8* data, int length) +{ + float left = channel.volume_l; + float right = channel.volume_r; + for (int i = 0; i < length * 2; i += 2) { + data[i] = (uint8)(data[i] * left); + data[i + 1] = (uint8)(data[i + 1] * right); + } +} + +bool Mixer::MustConvert(Stream& stream) +{ + const AudioFormat* streamformat = stream.Format(); + if (!streamformat) { + return false; + } + if (streamformat->format != format.format || streamformat->channels != format.channels || streamformat->freq != format.freq) { + return true; + } + return false; +} + +bool Mixer::Convert(SDL_AudioCVT& cvt, const uint8* data, unsigned long length, uint8** dataout) +{ + if (length == 0 || cvt.len_mult == 0) { + return false; + } + cvt.len = length; + cvt.buf = (Uint8*)new uint8[cvt.len * cvt.len_mult]; + memcpy(cvt.buf, data, length); + if (SDL_ConvertAudio(&cvt) < 0) { + delete[] cvt.buf; + return false; + } + *dataout = cvt.buf; + return true; +} + +void Mixer_Init(const char* device) +{ + gMixer.Init(device); +} + +void* Mixer_Play_Effect(int id, int loop, int volume, float pan, double rate, int deleteondone) +{ + if (id >= SOUND_MAXID) { + return 0; + } + gMixer.Lock(); + Channel* channel = gMixer.Play(gMixer.css1streams[id], loop, deleteondone != 0); + if (channel) { + channel->SetVolume(volume); + channel->SetPan(pan); + channel->SetRate(rate); + } + gMixer.Unlock(); + return channel; +} + +void Mixer_Stop_Channel(void* channel) +{ + gMixer.Stop(*(Channel*)channel); +} + +void Mixer_Channel_Volume(void* channel, int volume) +{ + gMixer.Lock(); + ((Channel*)channel)->SetVolume(volume); + gMixer.Unlock(); +} + +void Mixer_Channel_Pan(void* channel, float pan) +{ + gMixer.Lock(); + ((Channel*)channel)->SetPan(pan); + gMixer.Unlock(); +} + +void Mixer_Channel_Rate(void* channel, double rate) +{ + gMixer.Lock(); + ((Channel*)channel)->SetRate(rate); + gMixer.Unlock(); +} + +int Mixer_Channel_IsPlaying(void* channel) +{ + return ((Channel*)channel)->IsPlaying(); +} + +void* Mixer_Play_Music(int pathid) +{ + if (gMixer.LoadMusic(pathid)) { + return gMixer.Play(gMixer.musicstreams[pathid], MIXER_LOOP_INFINITE, false); + } + return 0; +} \ No newline at end of file diff --git a/src/audio/mixer.h b/src/audio/mixer.h new file mode 100644 index 0000000000..58c5c841ef --- /dev/null +++ b/src/audio/mixer.h @@ -0,0 +1,163 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of OpenRCT2. + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#ifndef _MIXER_H_ +#define _MIXER_H_ + +#include "../common.h" +#include + +#define USE_MIXER + +#define MIXER_LOOP_NONE 0 +#define MIXER_LOOP_INFINITE -1 + +#ifdef __cplusplus + +#include +extern "C" { +#include +} + +struct AudioFormat { + int BytesPerSample() const { return (SDL_AUDIO_BITSIZE(format)) / 8; }; + int freq; + SDL_AudioFormat format; + int channels; +}; + +class Sample +{ +public: + Sample(); + ~Sample(); + bool Load(const char* filename); + bool LoadCSS1(const char* filename, unsigned int offset); + void Unload(); + bool Loaded(); + bool Convert(AudioFormat format); + const uint8* Data(); + unsigned long Length(); + + friend class Stream; + +private: + AudioFormat format; + uint8* data; + unsigned long length; + bool issdlwav; +}; + +class Stream +{ +public: + Stream(); + unsigned long GetSome(unsigned long offset, const uint8** data, unsigned long length); + unsigned long Length(); + void SetSource_Sample(Sample& sample); + const AudioFormat* Format(); + + friend class Mixer; + +private: + enum { + SOURCE_NONE = 0, + SOURCE_SAMPLE + } sourcetype; + Sample* sample; +}; + +class Channel +{ +public: + Channel(); + ~Channel(); + void Play(Stream& stream, int loop); + void SetRate(double rate); + void SetVolume(int volume); + void SetPan(float pan); + bool IsPlaying(); + + friend class Mixer; + +private: + int loop; + unsigned long offset; + double rate; + int volume; + float volume_l, volume_r; + float pan; + bool done; + bool deleteondone; + SpeexResamplerState* resampler; + Stream* stream; +}; + +class Mixer +{ +public: + void Init(const char* device); + void Close(); + void Lock(); + void Unlock(); + Channel* Play(Stream& stream, int loop, bool deleteondone); + void Stop(Channel& channel); + bool LoadMusic(int pathid); + + Stream css1streams[SOUND_MAXID]; + Stream musicstreams[PATH_ID_END]; + +private: + static void SDLCALL Callback(void* arg, uint8* data, int length); + void MixChannel(Channel& channel, uint8* buffer, int length); + void EffectPanS16(Channel& channel, sint16* data, int length); + void EffectPanU8(Channel& channel, uint8* data, int length); + bool MustConvert(Stream& stream); + bool Convert(SDL_AudioCVT& cvt, const uint8* data, unsigned long length, uint8** dataout); + SDL_AudioDeviceID deviceid; + AudioFormat format; + uint8* effectbuffer; + Sample css1samples[SOUND_MAXID]; + Sample musicsamples[PATH_ID_END]; + std::list channels; +}; + +extern "C" +{ +#endif + +void Mixer_Init(const char* device); +void* Mixer_Play_Effect(int id, int loop, int volume, float pan, double rate, int deleteondone); +void Mixer_Stop_Channel(void* channel); +void Mixer_Channel_Volume(void* channel, int volume); +void Mixer_Channel_Pan(void* channel, float pan); +void Mixer_Channel_Rate(void* channel, double rate); +int Mixer_Channel_IsPlaying(void* channel); +void* Mixer_Play_Music(int pathid); + +static int DStoMixerVolume(int volume) { return (int)(SDL_MIX_MAXVOLUME * (SDL_pow(10, (float)volume / 2000))); }; +static float DStoMixerPan(int pan) { return (((float)pan + -DSBPAN_LEFT) / DSBPAN_RIGHT) / 2; }; +static double DStoMixerRate(int frequency) { return (double)frequency / 22050; }; + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/src/common.h b/src/common.h new file mode 100644 index 0000000000..e2bdc76314 --- /dev/null +++ b/src/common.h @@ -0,0 +1,26 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of OpenRCT2. + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#ifndef _COMMON_H_ +#define _COMMON_H_ + +#include "rct2.h" + +#endif \ No newline at end of file diff --git a/src/config.c b/src/config.c index 4dbd9117a0..d12a86bc26 100644 --- a/src/config.c +++ b/src/config.c @@ -23,11 +23,8 @@ #include #include "addresses.h" #include "config.h" -#include "language.h" -#include "rct2.h" - - -#include "osinterface.h" +#include "localisation/localisation.h" +#include "platform/osinterface.h" // Current keyboard shortcuts uint16 gShortcutKeys[SHORTCUT_COUNT]; diff --git a/src/config.h b/src/config.h index 43c9b25585..664d57eb58 100644 --- a/src/config.h +++ b/src/config.h @@ -21,9 +21,9 @@ #ifndef _CONFIG_H_ #define _CONFIG_H_ -#include "currency.h" -#include "rct2.h" #include // for MAX_PATH +#include "common.h" +#include "localisation/currency.h" enum { CONFIG_FLAG_ALWAYS_SHOW_GRIDLINES = (1 << 0), @@ -133,7 +133,7 @@ typedef struct general_configuration { uint16 language; } general_configuration_t; -static const struct { char *key; int value; } _currencyLookupTable[] = { +static const struct { const char *key; int value; } _currencyLookupTable[] = { { "GBP", CURRENCY_POUNDS }, { "USD", CURRENCY_DOLLARS }, { "FRF", CURRENCY_FRANC }, @@ -153,6 +153,11 @@ static const struct { char *key; int value; } _currencyLookupTable[] = { { "\xB5", CURRENCY_EUROS } }; +typedef struct shortcut_entry{ + uint8 key; + uint8 modifier; +}shortcut_entry; + //typedef struct hotkey_configuration{ //}; diff --git a/src/cursors.h b/src/cursors.h index efedd8e61d..531abf7e62 100644 --- a/src/cursors.h +++ b/src/cursors.h @@ -54,8 +54,8 @@ unsigned char up_arrow_cursor_mask[32 * 4] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; -#define UP_ARROW_CURSOR_HOTX 7 -#define UP_ARROW_CURSOR_HOTY 31 +#define UP_ARROW_CURSOR_HOTX 15 +#define UP_ARROW_CURSOR_HOTY 0 unsigned char up_down_arrow_cursor_data[32 * 4] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x02, 0xA0, 0x00, diff --git a/src/drawing/drawing.c b/src/drawing/drawing.c new file mode 100644 index 0000000000..247667a24a --- /dev/null +++ b/src/drawing/drawing.c @@ -0,0 +1,409 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John, Peter Hill, Duncan Frost + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of OpenRCT2. + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "../addresses.h" +#include "../common.h" +#include "../localisation/localisation.h" +#include "../interface/window.h" +#include "../platform/osinterface.h" +#include "drawing.h" + +// HACK These were originally passed back through registers +int gLastDrawStringX; +int gLastDrawStringY; + +uint8 _screenDirtyBlocks[5120]; + +//Originally 0x9ABE0C, 12 elements from 0xF3 are the peep top colour, 12 elements from 0xCA are peep trouser colour +const uint8 peep_palette[0x100] = { + 0x00, 0xF3, 0xF4, 0xF5, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, + 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, + 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF +}; + +//Originally 0x9ABE04 +uint8 text_palette[0x8] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +// Previously 0x97FCBC use it to get the correct palette from g1_elements +const uint16 palette_to_g1_offset[] = { + 0x1333, 0x1334, 0x1335, 0x1336, + 0x1337, 0x1338, 0x1339, 0x133A, + 0x133B, 0x133C, 0x133D, 0x133E, + 0x133F, 0x1340, 0x1341, 0x1342, + 0x1343, 0x1344, 0x1345, 0x1346, + 0x1347, 0x1348, 0x1349, 0x134A, + 0x134B, 0x134C, 0x134D, 0x134E, + 0x134F, 0x1350, 0x1351, 0x1352, + 0x1353, 0x0C1C, 0x0C1D, 0x0C1E, + 0x0C1F, 0x0C20, 0x0C22, 0x0C23, + 0x0C24, 0x0C25, 0x0C26, 0x0C21, + 0x1354, 0x1355, 0x1356, 0x1357, + 0x1358, 0x1359, 0x135A, 0x135B, + 0x135C, 0x135D, 0x135E, 0x135F, + 0x1360, 0x1361, 0x1362, 0x1363, + 0x1364, 0x1365, 0x1366, 0x1367, + 0x1368, 0x1369, 0x136A, 0x136B, + 0x136C, 0x136D, 0x136E, 0x136F, + 0x1370, 0x1371, 0x1372, 0x1373, + 0x1374, 0x1375, 0x1376, 0x1377, + 0x1378, 0x1379, 0x137A, 0x137B, + 0x137C, 0x137D, 0x137E, 0x137F, + 0x1380, 0x1381, 0x1382, 0x1383, + 0x1384, 0x1385, 0x1386, 0x1387, + 0x1388, 0x1389, 0x138A, 0x138B, + 0x138C, 0x138D, 0x138E, 0x138F, + 0x1390, 0x1391, 0x1392, 0x1393, + 0x1394, 0x1395, 0x1396, 0x1397, + 0x1398, 0x1399, 0x139A, 0x139B, + 0x139C, 0x139D, 0x139E, 0x139F, + 0x13A0, 0x13A1, 0x13A2, 0x13A3, + 0x13A4, 0x13A5, 0x13A6, 0x13A7, + 0x13A8, 0x13A9, 0x13AA, 0x13AB, + 0x13AC, 0x13AD, 0x13AE, 0x13AF, + 0x13B0, 0x13B1, 0x13B2, 0x13B3, + 0x13B4, 0x13B5, 0x13B6, 0x13B7, +}; + +static void gfx_draw_dirty_blocks(int x, int y, int columns, int rows); + +/** + * Clears the screen with the specified colour. + * rct2: 0x00678A9F + */ +void gfx_clear(rct_drawpixelinfo *dpi, int colour) +{ + int y, w, h; + char* ptr; + + w = dpi->width >> dpi->zoom_level; + h = dpi->height >> dpi->zoom_level; + + ptr = dpi->bits; + for (y = 0; y < h; y++) { + memset(ptr, colour, w); + ptr += w + dpi->pitch; + } +} + +void gfx_draw_pixel(rct_drawpixelinfo *dpi, int x, int y, int colour) +{ + gfx_fill_rect(dpi, x, y, x, y, colour); +} + +/** + * + * rct2: 0x00683854 + * a1 (ebx) + * product (cl) + */ +void gfx_transpose_palette(int pal, unsigned char product) +{ + rct_g1_element g1 = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[pal]; + int width = g1.width; + int x = g1.x_offset; + uint8* dest_pointer = (uint8*)&(RCT2_ADDRESS(0x014124680,uint8)[x]); + uint8* source_pointer = g1.offset; + + for (; width > 0; width--) { + dest_pointer[0] = (source_pointer[0] * product) >> 8; + dest_pointer[1] = (source_pointer[1] * product) >> 8; + dest_pointer[2] = (source_pointer[2] * product) >> 8; + source_pointer += 3; + dest_pointer += 4; + } + osinterface_update_palette((char*)0x01424680, 10, 236);//Odd would have expected dest_pointer +} + +/** + * + * rct2: 0x006ED7E5 + */ +void gfx_invalidate_screen() +{ + int width = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16); + int height = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16); + gfx_set_dirty_blocks(0, 0, width, height); +} + +/** + * + * rct2: 0x006E732D + * left (ax) + * top (bx) + * right (dx) + * bottom (bp) + */ +void gfx_set_dirty_blocks(int left, int top, int right, int bottom) +{ + int x, y; + uint8 *screenDirtyBlocks = RCT2_ADDRESS(0x00EDE408, uint8); + + left = max(left, 0); + top = max(top, 0); + right = min(right, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16)); + bottom = min(bottom, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16)); + + if (left >= right) + return; + if (top >= bottom) + return; + + right--; + bottom--; + + left >>= RCT2_GLOBAL(0x009ABDF0, sint8); + right >>= RCT2_GLOBAL(0x009ABDF0, sint8); + top >>= RCT2_GLOBAL(0x009ABDF1, sint8); + bottom >>= RCT2_GLOBAL(0x009ABDF1, sint8); + + for (y = top; y <= bottom; y++) + for (x = left; x <= right; x++) + screenDirtyBlocks[y * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_COLUMNS, sint32) + x] = 0xFF; +} + +/** + * + * rct2: 0x006E73BE + */ +void gfx_draw_all_dirty_blocks() +{ + int x, y, xx, yy, columns, rows; + uint8 *screenDirtyBlocks = RCT2_ADDRESS(0x00EDE408, uint8); + + for (x = 0; x < RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_COLUMNS, sint32); x++) { + for (y = 0; y < RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_ROWS, sint32); y++) { + if (screenDirtyBlocks[y * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_COLUMNS, sint32) + x] == 0) + continue; + + // Determine columns + for (xx = x; xx < RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_COLUMNS, sint32); xx++) + if (screenDirtyBlocks[y * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_COLUMNS, sint32) + xx] == 0) + break; + columns = xx - x; + + // Check rows + for (yy = y; yy < RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_ROWS, sint32); yy++) + for (xx = x; xx < x + columns; xx++) + if (screenDirtyBlocks[yy * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_COLUMNS, sint32) + xx] == 0) + goto endRowCheck; + + endRowCheck: + rows = yy - y; + gfx_draw_dirty_blocks(x, y, columns, rows); + } + } +} + +static void gfx_draw_dirty_blocks(int x, int y, int columns, int rows) +{ + int left, top, right, bottom; + uint8 *screenDirtyBlocks = RCT2_ADDRESS(0x00EDE408, uint8); + + // Unset dirty blocks + for (top = y; top < y + rows; top++) + for (left = x; left < x + columns; left++) + screenDirtyBlocks[top * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_COLUMNS, sint32) + left] = 0; + + // Determine region in pixels + left = max(0, x * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_WIDTH, sint16)); + top = max(0, y * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_HEIGHT, sint16)); + right = min(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16), left + (columns * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_WIDTH, sint16))); + bottom = min(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16), top + (rows * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_HEIGHT, sint16))); + if (right <= left || bottom <= top) + return; + + // Draw region + gfx_redraw_screen_rect(left, top, right, bottom); +} + +/** + * + * rct2: 0x006E7499 + * left (ax) + * top (bx) + * right (dx) + * bottom (bp) + */ +void gfx_redraw_screen_rect(short left, short top, short right, short bottom) +{ + rct_window* w; + rct_drawpixelinfo *screenDPI = RCT2_ADDRESS(RCT2_ADDRESS_SCREEN_DPI, rct_drawpixelinfo); + rct_drawpixelinfo *windowDPI = RCT2_ADDRESS(RCT2_ADDRESS_WINDOW_DPI, rct_drawpixelinfo); + + // Unsure what this does + RCT2_CALLPROC_X(0x00683326, left, top, right - 1, bottom - 1, 0, 0, 0); + + windowDPI->bits = screenDPI->bits + left + ((screenDPI->width + screenDPI->pitch) * top); + windowDPI->x = left; + windowDPI->y = top; + windowDPI->width = right - left; + windowDPI->height = bottom - top; + windowDPI->pitch = screenDPI->width + screenDPI->pitch + left - right; + + for (w = g_window_list; w < RCT2_GLOBAL(RCT2_ADDRESS_NEW_WINDOW_PTR, rct_window*); w++) { + if (w->flags & WF_TRANSPARENT) + continue; + if (right <= w->x || bottom <= w->y) + continue; + if (left >= w->x + w->width || top >= w->y + w->height) + continue; + window_draw(w, left, top, right, bottom); + } +} + +/* +* +* rct2: 0x006EE53B +* left (ax) +* width (bx) +* top (cx) +* height (dx) +* drawpixelinfo (edi) +*/ +rct_drawpixelinfo* clip_drawpixelinfo(rct_drawpixelinfo* dpi, int left, int width, int top, int height) +{ + rct_drawpixelinfo* newDrawPixelInfo = rct2_malloc(sizeof(rct_drawpixelinfo)); + + int right = left + width; + int bottom = top + height; + + newDrawPixelInfo->bits = dpi->bits; + newDrawPixelInfo->x = dpi->x; + newDrawPixelInfo->y = dpi->y; + newDrawPixelInfo->width = dpi->width; + newDrawPixelInfo->height = dpi->height; + newDrawPixelInfo->pitch = dpi->pitch; + newDrawPixelInfo->zoom_level = 0; + + if (left > newDrawPixelInfo->x) { + uint16 clippedFromLeft = left - newDrawPixelInfo->x; + newDrawPixelInfo->width -= clippedFromLeft; + newDrawPixelInfo->x = left; + newDrawPixelInfo->pitch += clippedFromLeft; + newDrawPixelInfo->bits += clippedFromLeft; + } + + int stickOutWidth = newDrawPixelInfo->x + newDrawPixelInfo->width - right; + if (stickOutWidth > 0) { + newDrawPixelInfo->width -= stickOutWidth; + newDrawPixelInfo->pitch += stickOutWidth; + } + + if (top > newDrawPixelInfo->y) { + uint16 clippedFromTop = top - newDrawPixelInfo->y; + newDrawPixelInfo->height -= clippedFromTop; + newDrawPixelInfo->y = top; + uint32 bitsPlus = (newDrawPixelInfo->pitch + newDrawPixelInfo->width) * clippedFromTop; + newDrawPixelInfo->bits += bitsPlus; + } + + int bp = newDrawPixelInfo->y + newDrawPixelInfo->height - bottom; + if (bp > 0) { + newDrawPixelInfo->height -= bp; + } + + if (newDrawPixelInfo->width > 0 && newDrawPixelInfo->height > 0) { + newDrawPixelInfo->x -= left; + newDrawPixelInfo->y -= top; + + return newDrawPixelInfo; + } + + rct2_free(newDrawPixelInfo); + return NULL; +} + +/*** +* +* rct2: 0x00684027 +* +* ebp used to be a parameter but it is always zero +* left : eax +* top : ebx +* width : ecx +* height : edx +* x_start: edi +* y_start: esi +*/ +void gfx_draw_rain(int left, int top, int width, int height, sint32 x_start, sint32 y_start){ + uint8* pattern = RCT2_GLOBAL(RCT2_ADDRESS_RAIN_PATTERN, uint8*); + uint8 pattern_x_space = *pattern++; + uint8 pattern_y_space = *pattern++; + + uint8 pattern_start_x_offset = x_start % pattern_x_space; + uint8 pattern_start_y_offset = y_start % pattern_y_space;; + + rct_drawpixelinfo* dpi = RCT2_ADDRESS(RCT2_ADDRESS_SCREEN_DPI, rct_drawpixelinfo); + uint32 pixel_offset = (dpi->pitch + dpi->width)*top + left; + uint8 pattern_y_pos = pattern_start_y_offset; + + //Stores the colours of changed pixels + uint32* pixel_store = RCT2_ADDRESS(RCT2_ADDRESS_RAIN_PIXEL_STORE, uint32); + pixel_store += RCT2_GLOBAL(RCT2_ADDRESS_NO_RAIN_PIXELS, uint32); + + for (; height != 0; height--){ + uint8 pattern_x = pattern[pattern_y_pos * 2]; + if (pattern_x != 0xFF){ + if (RCT2_GLOBAL(0x9AC00C, uint32) <= 0x1F38){ + + int final_pixel_offset = width + pixel_offset; + + int x_pixel_offset = pixel_offset; + x_pixel_offset += ((uint8)(pattern_x - pattern_start_x_offset)) % pattern_x_space; + + uint8 pattern_pixel = pattern[pattern_y_pos * 2 + 1]; + for (; x_pixel_offset < final_pixel_offset; x_pixel_offset += pattern_x_space){ + uint8 current_pixel = dpi->bits[x_pixel_offset]; + dpi->bits[x_pixel_offset] = pattern_pixel; + RCT2_GLOBAL(RCT2_ADDRESS_NO_RAIN_PIXELS, uint32)++; + + //Store colour and position + *pixel_store++ = (x_pixel_offset << 8) | current_pixel; + } + } + } + + pixel_offset += dpi->pitch + dpi->width; + + pattern_y_pos++; + pattern_y_pos %= pattern_y_space; + } +} \ No newline at end of file diff --git a/src/gfx.h b/src/drawing/drawing.h similarity index 82% rename from src/gfx.h rename to src/drawing/drawing.h index 11e9875f76..a9dabe0648 100644 --- a/src/gfx.h +++ b/src/drawing/drawing.h @@ -18,10 +18,10 @@ * along with this program. If not, see . *****************************************************************************/ -#ifndef _GFX_H_ -#define _GFX_H_ +#ifndef _DRAWING_H_ +#define _DRAWING_H_ -#include "rct2.h" +#include "../common.h" // Size: 0x10 typedef struct { @@ -58,45 +58,61 @@ enum{ IMAGE_TYPE_UNKNOWN = (1<<3) }; +extern const uint16 palette_to_g1_offset[]; +extern const uint8 peep_palette[]; +extern uint8 text_palette[]; + extern int gLastDrawStringX; extern int gLastDrawStringY; -int gfx_load_g1(); -void gfx_load_character_widths(); - -int gfx_wrap_string(char* buffer, int width, int* num_lines, int* font_height); -void gfx_clear(rct_drawpixelinfo *dpi, int colour); -void gfx_draw_pixel(rct_drawpixelinfo *dpi, int x, int y, int colour); -void gfx_draw_line(rct_drawpixelinfo *dpi, int x1, int y1, int x2, int y2, int colour); -void gfx_fill_rect(rct_drawpixelinfo *dpi, int left, int top, int right, int bottom, int colour); -void gfx_fill_rect_inset(rct_drawpixelinfo* dpi, short left, short top, short right, short bottom, int colour, short _si); -void gfx_draw_sprite(rct_drawpixelinfo *dpi, int image_id, int x, int y, uint32 tertiary_colour); -void gfx_draw_sprite_palette_set(rct_drawpixelinfo *dpi, int image_id, int x, int y, uint8* palette_pointer, uint8* unknown_pointer); -void gfx_draw_string(rct_drawpixelinfo *dpi, char *buffer, int colour, int x, int y); -void gfx_transpose_palette(int pal, unsigned char product); - -void gfx_draw_string_left(rct_drawpixelinfo *dpi, int format, void *args, int colour, int x, int y); -void gfx_draw_string_left_clipped(rct_drawpixelinfo *dpi, int format, void *args, int colour, int x, int y, int width); -void gfx_draw_string_centred_clipped(rct_drawpixelinfo *dpi, int format, void *args, int colour, int x, int y, int width); -void gfx_draw_string_right(rct_drawpixelinfo *dpi, int format, void *args, int colour, int x, int y); -void gfx_draw_string_centred(rct_drawpixelinfo *dpi, int format, int x, int y, int colour, void *args); -int gfx_draw_string_centred_wrapped(rct_drawpixelinfo *dpi, void *args, int x, int y, int width, int format, int colour); -int gfx_draw_string_left_wrapped(rct_drawpixelinfo *dpi, void *args, int x, int y, int width, int format, int colour); - -int gfx_get_string_width(char *buffer); -int clip_text(char *buffer, int width); -void gfx_fill_rect_inset(rct_drawpixelinfo *dpi, short left, short top, short right, short bottom, int colour, short _si); - +// +rct_drawpixelinfo* clip_drawpixelinfo(rct_drawpixelinfo* dpi, int left, int width, int top, int height); void gfx_set_dirty_blocks(int left, int top, int right, int bottom); void gfx_draw_all_dirty_blocks(); void gfx_redraw_screen_rect(short left, short top, short right, short bottom); void gfx_invalidate_screen(); +// palette +void gfx_transpose_palette(int pal, unsigned char product); + +// other void gfx_draw_rain(int left, int top, int width, int height, sint32 x_start, sint32 y_start); +void gfx_clear(rct_drawpixelinfo *dpi, int colour); +void gfx_draw_pixel(rct_drawpixelinfo *dpi, int x, int y, int colour); -rct_drawpixelinfo* clip_drawpixelinfo(rct_drawpixelinfo* dpi, int left, int width, int top, int height); +// line +void gfx_draw_line(rct_drawpixelinfo *dpi, int x1, int y1, int x2, int y2, int colour); +// rect +void gfx_fill_rect(rct_drawpixelinfo *dpi, int left, int top, int right, int bottom, int colour); +void gfx_fill_rect_inset(rct_drawpixelinfo* dpi, short left, short top, short right, short bottom, int colour, short _si); + +// sprite +int gfx_load_g1(); +void gfx_bmp_sprite_to_buffer(uint8* palette_pointer, uint8* unknown_pointer, uint8* source_pointer, uint8* dest_pointer, rct_g1_element* source_image, rct_drawpixelinfo *dest_dpi, int height, int width, int image_type); +void gfx_rle_sprite_to_buffer(uint8* source_bits_pointer, uint8* dest_bits_pointer, uint8* palette_pointer, rct_drawpixelinfo *dpi, int image_type, int source_y_start, int height, int source_x_start, int width); +void gfx_draw_sprite(rct_drawpixelinfo *dpi, int image_id, int x, int y, uint32 tertiary_colour); +void gfx_draw_sprite_palette_set(rct_drawpixelinfo *dpi, int image_id, int x, int y, uint8* palette_pointer, uint8* unknown_pointer); + +// string +void gfx_load_character_widths(); +int clip_text(char *buffer, int width); +int gfx_wrap_string(char* buffer, int width, int* num_lines, int* font_height); +int gfx_get_string_width(char *buffer); +void gfx_draw_string(rct_drawpixelinfo *dpi, char *buffer, int colour, int x, int y); +void gfx_draw_string_left(rct_drawpixelinfo *dpi, int format, void *args, int colour, int x, int y); +void gfx_draw_string_left_clipped(rct_drawpixelinfo *dpi, int format, void *args, int colour, int x, int y, int width); +int gfx_draw_string_left_wrapped(rct_drawpixelinfo *dpi, void *args, int x, int y, int width, int format, int colour); void draw_string_left_underline(rct_drawpixelinfo *dpi, int format, void *args, int colour, int x, int y); +void gfx_draw_string_centred(rct_drawpixelinfo *dpi, int format, int x, int y, int colour, void *args); +void gfx_draw_string_centred_clipped(rct_drawpixelinfo *dpi, int format, void *args, int colour, int x, int y, int width); +void draw_string_centred_underline(rct_drawpixelinfo *dpi, int format, void *args, int colour, int x, int y); +int gfx_draw_string_centred_wrapped(rct_drawpixelinfo *dpi, void *args, int x, int y, int width, int format, int colour); +void draw_string_centred_raw(rct_drawpixelinfo *dpi, int x, int y, int numLines, char *text); +void gfx_draw_string_right(rct_drawpixelinfo *dpi, int format, void *args, int colour, int x, int y); void draw_string_right_underline(rct_drawpixelinfo *dpi, int format, void *args, int colour, int x, int y); +// rain +void update_rain_animation(); + #endif diff --git a/src/drawing/line.c b/src/drawing/line.c new file mode 100644 index 0000000000..28bfbe7db6 --- /dev/null +++ b/src/drawing/line.c @@ -0,0 +1,150 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John, Peter Hill, Duncan Frost + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of OpenRCT2. + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#include "drawing.h" + +/* + * Draws a horizontal line of specified colour to a buffer. + * rct2: 0x0068474C + */ +void gfx_draw_line_on_buffer(rct_drawpixelinfo *dpi, char colour, int y, int x, int no_pixels) +{ + y -= dpi->y; + + //Check to make sure point is in the y range + if (y < 0)return; + if (y >= dpi->height)return; + //Check to make sure we are drawing at least a pixel + if (!no_pixels) no_pixels++; + + x -= dpi->x; + + //If x coord outside range leave + if (x < 0){ + //Unless the number of pixels is enough to be in range + no_pixels += x; + if (no_pixels <= 0)return; + //Resets starting point to 0 as we don't draw outside the range + x = 0; + } + + //Ensure that the end point of the line is within range + if (x + no_pixels - dpi->width > 0){ + //If the end point has any pixels outside range + //cut them off. If there are now no pixels return. + no_pixels -= x + no_pixels - dpi->width; + if (no_pixels <= 0)return; + } + + char* bits_pointer; + //Get the buffer we are drawing to and move to the first coordinate. + bits_pointer = dpi->bits + y*(dpi->pitch + dpi->width) + x; + + //Draw the line to the specified colour + for (; no_pixels > 0; --no_pixels, ++bits_pointer){ + *((uint8*)bits_pointer) = colour; + } +} + +/** + * Draws a line on dpi if within dpi boundaries + * rct2: 0x00684466 + * dpi (edi) + * x1 (ax) + * y1 (bx) + * x2 (cx) + * y2 (dx) + * colour (ebp) + */ +void gfx_draw_line(rct_drawpixelinfo *dpi, int x1, int y1, int x2, int y2, int colour) +{ + // Check to make sure the line is within the drawing area + if ((x1 < dpi->x) && (x2 < dpi->x)){ + return; + } + + if ((y1 < dpi->y) && (y2 < dpi->y)){ + return; + } + + if ((x1 >(dpi->x + dpi->width)) && (x2 >(dpi->x + dpi->width))){ + return; + } + + if ((y1 > (dpi->y + dpi->height)) && (y2 > (dpi->y + dpi->height))){ + return; + } + + //Bresenhams algorithm + + //If vertical plot points upwards + int steep = abs(y2 - y1) > abs(x2 - x1); + if (steep){ + int temp_y2 = y2; + int temp_x2 = x2; + y2 = x1; + x2 = y1; + y1 = temp_x2; + x1 = temp_y2; + } + + //If line is right to left swap direction + if (x1 > x2){ + int temp_y2 = y2; + int temp_x2 = x2; + y2 = y1; + x2 = x1; + y1 = temp_y2; + x1 = temp_x2; + } + + int delta_x = x2 - x1; + int delta_y = abs(y2 - y1); + int error = delta_x / 2; + int y_step; + int y = y1; + + //Direction of step + if (y1 < y2)y_step = 1; + else y_step = -1; + + for (int x = x1, x_start = x1, no_pixels = 1; x < x2; ++x,++no_pixels){ + //Vertical lines are drawn 1 pixel at a time + if (steep)gfx_draw_line_on_buffer(dpi, colour, x, y, 1); + + error -= delta_y; + if (error < 0){ + //Non vertical lines are drawn with as many pixels in a horizontal line as possible + if (!steep)gfx_draw_line_on_buffer(dpi, colour, y, x_start, no_pixels); + + //Reset non vertical line vars + x_start = x + 1; + no_pixels = 1; + y += y_step; + error += delta_x; + } + + //Catch the case of the last line + if (x + 1 == x2 && !steep){ + gfx_draw_line_on_buffer(dpi, colour, y, x_start, no_pixels); + } + } + return; +} \ No newline at end of file diff --git a/src/drawing/rain.c b/src/drawing/rain.c new file mode 100644 index 0000000000..b1660e5fb6 --- /dev/null +++ b/src/drawing/rain.c @@ -0,0 +1,239 @@ +/***************************************************************************** + * Copyright (c) 2014 + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of OpenRCT2. + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#include "../addresses.h" +#include "../interface/window.h" +#include "drawing.h" + +typedef void(*draw_rain_func)(int left, int top, int width, int height); + +static void draw_light_rain(int left, int top, int width, int height); +static void draw_heavy_rain(int left, int top, int width, int height); + +/** + * + * rct2: 0x009AC058 + */ +const draw_rain_func draw_rain_function[] = { + NULL, + &draw_light_rain, + &draw_heavy_rain +}; + +/** + * + * rct2: 0x00684383 + */ +static void call_draw_rain_func(rct_window* w, short left, short right, short top, short bottom, uint32 draw_rain_func) +{ + rct_viewport* vp = w->viewport; + if (vp == NULL) { + return; + } + + left = max(left, vp->x); + right = min(right, vp->width); + + top = max(top, vp->y); + bottom = min(bottom, vp->height); + + if (left >= right || top >= bottom) { + return; + } + + int width = right - left; + int height = bottom - top; + + draw_rain_function[draw_rain_func](left, top, width, height); +} + +/** + * + * rct2: 0x006842AF + * From 0x00684383 on: split into call_draw_rain_func + */ +static void draw_rain_window(rct_window* original_w, short left, short right, short top, short bottom, uint32 draw_rain_func) +{ + rct_window* newWindow = RCT2_GLOBAL(RCT2_ADDRESS_NEW_WINDOW_PTR, rct_window*); + + rct_window* w = original_w + 1; // Start from second window + for (; ; w++) { + if (w >= newWindow) { + // Loop ended, draw rain for original_w + call_draw_rain_func(original_w, left, right, top, bottom, draw_rain_func); + return; + } + + if (right <= w->x || bottom <= w->y) { + continue; + } + + if (RCT_WINDOW_RIGHT(w) <= left || RCT_WINDOW_BOTTOM(w) <= top) { + continue; + } + + if (left >= w->x) { + break; + } + + draw_rain_window(original_w, left, w->x, top, bottom, draw_rain_func); + + left = w->x; + draw_rain_window(original_w, left, right, top, bottom, draw_rain_func); + return; + } + + sint16 w_right = RCT_WINDOW_RIGHT(w); + if (right > w_right) { + draw_rain_window(original_w, left, w_right, top, bottom, draw_rain_func); + + left = w_right; + draw_rain_window(original_w, left, right, top, bottom, draw_rain_func); + return; + } + + if (top < w->y) { + draw_rain_window(original_w, left, right, top, w->y, draw_rain_func); + + top = w->y; + draw_rain_window(original_w, left, right, top, bottom, draw_rain_func); + return; + } + + sint16 w_bottom = RCT_WINDOW_BOTTOM(w); + if (bottom > w_bottom) { + draw_rain_window(original_w, left, right, top, w_bottom, draw_rain_func); + + top = w_bottom; + draw_rain_window(original_w, left, right, top, bottom, draw_rain_func); + return; + } +} + +/** + * + * rct2: 0x00684266 + */ +static void draw_rain_animation(uint32 draw_rain_func) +{ + rct_drawpixelinfo *screenDPI = RCT2_ADDRESS(RCT2_ADDRESS_SCREEN_DPI, rct_drawpixelinfo); + short left = screenDPI->x; + short right = left + screenDPI->width; + short top = screenDPI->y; + short bottom = top + screenDPI->height; + + rct_window* newWindow = (RCT2_GLOBAL(RCT2_ADDRESS_NEW_WINDOW_PTR, rct_window*)); + + for (rct_window* w = g_window_list; w < newWindow; w++) { + draw_rain_window(w, left, right, top, bottom, draw_rain_func); + } +} + +/** + * + * rct2: 0x00684218 + */ +void update_rain_animation() +{ + if (RCT2_GLOBAL(0x009ABDF2, uint8) == 0) + return; + + // Draw picked-up peep + if (RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_SPRITE, uint32) != 0xFFFFFFFF) { + gfx_draw_sprite( + (rct_drawpixelinfo*)RCT2_ADDRESS_SCREEN_DPI, + RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_SPRITE, uint32), + RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_X, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_Y, sint16), 0 + ); + } + + // Get rain draw function and draw rain + uint32 draw_rain_func = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_RAIN_LEVEL, uint8); + if (draw_rain_func > 0 && !(RCT2_GLOBAL(0x009DEA6F, uint8) & 1)) + draw_rain_animation(draw_rain_func); +} + +/** + * + * rct2: 0x00684114 + */ +static void draw_light_rain(int left, int top, int width, int height) +{ + int x_start = -RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int) + 8; + int y_start = (RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int) * 3) + 7; + y_start = -y_start; + + x_start += left; + y_start += top; + + gfx_draw_rain(left, top, width, height, x_start, y_start); + + x_start = -RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int) + 0x18; + y_start = (RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int) * 4) + 0x0D; + y_start = -y_start; + + x_start += left; + y_start += top; + gfx_draw_rain(left, top, width, height, x_start, y_start); +} + +/** + * + * rct2: 0x0068416D + */ +static void draw_heavy_rain(int left, int top, int width, int height) +{ + int x_start = -RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int); + int y_start = RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int) * 5; + y_start = -y_start; + + x_start += left; + y_start += top; + + gfx_draw_rain(left, top, width, height, x_start, y_start); + + x_start = -RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int) + 0x10; + y_start = (RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int) * 6) + 5; + y_start = -y_start; + + x_start += left; + y_start += top; + + gfx_draw_rain(left, top, width, height, x_start, y_start); + + x_start = -RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int) + 8; + y_start = (RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int) * 3) + 7; + y_start = -y_start; + + x_start += left; + y_start += top; + + gfx_draw_rain(left, top, width, height, x_start, y_start); + + x_start = -RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int) + 0x18; + y_start = (RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int) * 4) + 0x0D; + y_start = -y_start; + + x_start += left; + y_start += top; + + gfx_draw_rain(left, top, width, height, x_start, y_start); +} \ No newline at end of file diff --git a/src/drawing/rect.c b/src/drawing/rect.c new file mode 100644 index 0000000000..c23f881b56 --- /dev/null +++ b/src/drawing/rect.c @@ -0,0 +1,329 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John, Peter Hill, Duncan Frost + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of OpenRCT2. + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#include "../addresses.h" +#include "../common.h" +#include "drawing.h" + +/** + * + * rct2: 0x00678AD4 + * dpi (edi) + * left (ax) + * top (cx) + * right (bx) + * bottom (dx) + * colour (ebp) + */ +void gfx_fill_rect(rct_drawpixelinfo *dpi, int left, int top, int right, int bottom, int colour) +{ + int left_, right_, top_, bottom_; + rct_drawpixelinfo* dpi_; + left_ = left; + right_ = right; + top_ = top; + bottom_ = bottom; + dpi_ = dpi; + + if ((left > right) || (top > bottom) || (dpi->x > right) || (left >= (dpi->x + dpi->width)) || + (bottom < dpi->y) || (top >= (dpi->y + dpi->height))) + return; + + colour |= RCT2_GLOBAL(0x009ABD9C, uint32); + + uint16 cross_pattern = 0; + + int start_x = left - dpi->x; + if (start_x < 0){ + start_x = 0; + cross_pattern ^= start_x; + } + + int end_x = right - dpi->x; + end_x++; + if (end_x > dpi->width) + end_x = dpi->width; + + int width = end_x - start_x; + + int start_y = top - dpi->y; + if (start_y < 0){ + start_y = 0; + cross_pattern ^= start_y; + } + int end_y = bottom - dpi->y; + end_y++; + + if (end_y > dpi->height) + end_y = dpi->height; + + int height = end_y - start_y; + if (colour&0x1000000){ + // 00678B2E 00678BE5 + //Cross hatching + uint8* dest_pointer = (start_y * (dpi->width + dpi->pitch)) + start_x + dpi->bits; + + uint32 ecx; + for (int i = 0; i < height; ++i) { + uint8* next_dest_pointer = dest_pointer + dpi->width + dpi->pitch; + ecx = cross_pattern; + // Rotate right + ecx = (ecx >> 1) | (ecx << (sizeof(ecx) * CHAR_BIT - 1)); + ecx = (ecx & 0xFFFF0000) | width; + // Fill every other pixel with the colour + for (; (ecx & 0xFFFF) > 0; ecx--) { + ecx = ecx ^ 0x80000000; + if ((int)ecx < 0) { + *dest_pointer = colour & 0xFF; + } + dest_pointer++; + } + cross_pattern ^= 1; + dest_pointer = next_dest_pointer; + + } + return; + } + if (colour & 0x2000000){ + //0x2000000 + // 00678B7E 00678C83 + // Location in screen buffer? + uint8* dest_pointer = dpi->bits + (uint32)((start_y >> (dpi->zoom_level)) * ((dpi->width >> dpi->zoom_level) + dpi->pitch) + (start_x >> dpi->zoom_level)); + + // Find colour in colour table? + uint16 eax = palette_to_g1_offset[(colour & 0xFF)]; + rct_g1_element g1_element = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[eax]; + + // Fill the rectangle with the colours from the colour table + for (int i = 0; i < height>>dpi->zoom_level; ++i) { + uint8* next_dest_pointer = dest_pointer + (dpi->width >> dpi->zoom_level) + dpi->pitch; + for (int j = 0; j < width; ++j) { + *dest_pointer = g1_element.offset[*dest_pointer]; + dest_pointer++; + } + dest_pointer = next_dest_pointer; + } + return; + } + if (colour & 0x4000000){ + //0x4000000 + // 00678B8A 00678E38 + char* dest_pointer; + dest_pointer = start_y * (dpi->width + dpi->pitch) + start_x + dpi->bits; + + //The pattern loops every 15 lines this is which + //part the pattern is on. + int pattern_y = (start_y + dpi->y) % 16; + + //The pattern loops every 15 pixels this is which + //part the pattern is on. + int start_pattern_x = (start_x + dpi_->x) % 16; + int pattern_x = start_pattern_x; + + uint16* pattern_pointer; + pattern_pointer = RCT2_ADDRESS(0x0097FEFC,uint16*)[colour >> 28]; // or possibly uint8)[esi*4] ? + + for (int no_lines = height; no_lines > 0; no_lines--) { + char* next_dest_pointer = dest_pointer + dpi->width + dpi->pitch; + uint16 pattern = pattern_pointer[pattern_y]; + + for (int no_pixels = width; no_pixels > 0; --no_pixels) { + if (pattern & (1 << pattern_x)) + *dest_pointer = colour & 0xFF; + + pattern_x = (pattern_x + 1) % 16; + dest_pointer++; + } + pattern_x = start_pattern_x; + pattern_y = (pattern_y + 1) % 16; + dest_pointer = next_dest_pointer; + } + return; + } + if (colour & 0x8000000){ + //0x8000000 + // 00678B3A 00678EC9 still to be implemented + //RCT2_CALLPROC_X(0x00678AD4, left, right, top, bottom, 0, dpi, colour); + int esi = left - RCT2_GLOBAL(0x1420070,sint16); + RCT2_GLOBAL(0xEDF824,uint32) = esi; + esi = top - RCT2_GLOBAL(0x1420072,sint16); + RCT2_GLOBAL(0xEDF828,uint32) = esi; + left -= dpi->x;//0x4 + if ( left < 0 ){ + RCT2_GLOBAL(0xEDF824,sint32) -= left; + left = 0; + } + right -= dpi->x; + right++; + if ( right > dpi->width ){ + right = dpi->width; + } + right -= left; + top -= dpi->y; + if ( top < 0 ){ + RCT2_GLOBAL(0xEDF828,sint32) -= top; + top = 0; + } + bottom -= dpi->y; + bottom++; + if (bottom > dpi->height){ + bottom = dpi->height; + } + bottom -= top; + RCT2_GLOBAL(0xEDF824,sint32) &= 0x3F; + RCT2_GLOBAL(0xEDF828,sint32) &= 0x3F; + esi = dpi->width; + esi += dpi->pitch; + esi *= top; + esi += left; + esi += (uint32)dpi->bits; + RCT2_GLOBAL(0xEDF82C,sint32) = right; + RCT2_GLOBAL(0xEDF830,sint32) = bottom; + left = dpi->width; + left+= dpi->pitch; + left-= right; + RCT2_GLOBAL(0xEDF834,sint32) = left; + colour &= 0xFF; + colour--; + right = colour; + colour <<= 8; + right |= colour; + RCT2_GLOBAL(0xEDF838,sint32) = right; + //right <<= 4; + int edi = esi; + esi = RCT2_GLOBAL(0xEDF828,sint32); + esi *= 0x40; + left = 0; + esi += (uint32)(RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS,rct_g1_element)[right]).offset;//??? + //Not finished + //Start of loop + return; + } + //0x0000000 + uint8* dest_pointer = start_y * (dpi->width + dpi->pitch) + start_x + dpi->bits; + + for (int i = 0; i < height; ++i) { + memset(dest_pointer, (colour & 0xFF), width); + dest_pointer += dpi->width + dpi->pitch; + } + // RCT2_CALLPROC_X(0x00678AD4, left, right, top, bottom, 0, dpi, colour); +} + +/** + * Draw a rectangle, with optional border or fill + * + * rct2: 0x006E6F81 + * dpi (edi) + * left (ax) + * top (cx) + * right (bx) + * bottom (dx) + * colour (ebp) + * flags (si) + */ +void gfx_fill_rect_inset(rct_drawpixelinfo* dpi, short left, short top, short right, short bottom, int colour, short flags) +{ + uint8 shadow, fill, hilight; + + // Flags + int no_border, no_fill, pressed; + + no_border = 8; + no_fill = 0x10; + pressed = 0x20; + + if (colour & 0x180) { + if (colour & 0x100) { + colour = colour & 0x7F; + } else { + colour = RCT2_ADDRESS(0x009DEDF4,uint8)[colour]; + } + + colour = colour | 0x2000000; //Transparent + + if (flags & no_border) { + gfx_fill_rect(dpi, left, top, bottom, right, colour); + } else if (flags & pressed) { + // Draw outline of box + gfx_fill_rect(dpi, left, top, left, bottom, colour + 1); + gfx_fill_rect(dpi, left, top, right, top, colour + 1); + gfx_fill_rect(dpi, right, top, right, bottom, colour + 2); + gfx_fill_rect(dpi, left, bottom, right, bottom, colour + 2); + + if (!(flags & no_fill)) { + gfx_fill_rect(dpi, left+1, top+1, right-1, bottom-1, colour); + } + } else { + // Draw outline of box + gfx_fill_rect(dpi, left, top, left, bottom, colour + 2); + gfx_fill_rect(dpi, left, top, right, top, colour + 2); + gfx_fill_rect(dpi, right, top, right, bottom, colour + 1); + gfx_fill_rect(dpi, left, bottom, right, bottom, colour + 1); + + if (!(flags & no_fill)) { + gfx_fill_rect(dpi, left+1, top+1, right-1, bottom-1, colour); + } + } + } else { + if (flags & 0x80) { + shadow = RCT2_ADDRESS(0x0141FC46, uint8)[colour * 8]; + fill = RCT2_ADDRESS(0x0141FC48, uint8)[colour * 8]; + hilight = RCT2_ADDRESS(0x0141FC4A, uint8)[colour * 8]; + } else { + shadow = RCT2_ADDRESS(0x0141FC47, uint8)[colour * 8]; + fill = RCT2_ADDRESS(0x0141FC49, uint8)[colour * 8]; + hilight = RCT2_ADDRESS(0x0141FC4B, uint8)[colour * 8]; + } + + if (flags & no_border) { + gfx_fill_rect(dpi, left, top, right, bottom, fill); + } else if (flags & pressed) { + // Draw outline of box + gfx_fill_rect(dpi, left, top, left, bottom, shadow); + gfx_fill_rect(dpi, left + 1, top, right, top, shadow); + gfx_fill_rect(dpi, right, top + 1, right, bottom - 1, hilight); + gfx_fill_rect(dpi, left + 1, bottom, right, bottom, hilight); + + if (!(flags & no_fill)) { + if (!(flags & 0x40)) { + if (flags & 0x04) { + fill = RCT2_ADDRESS(0x0141FC49, uint8)[0]; + } else { + fill = RCT2_ADDRESS(0x0141FC4A, uint8)[colour * 8]; + } + } + gfx_fill_rect(dpi, left+1, top+1, right-1, bottom-1, fill); + } + } else { + // Draw outline of box + gfx_fill_rect(dpi, left, top, left, bottom - 1, hilight); + gfx_fill_rect(dpi, left + 1, top, right - 1, top, hilight); + gfx_fill_rect(dpi, right, top, right, bottom - 1, shadow); + gfx_fill_rect(dpi, left, bottom, right, bottom, shadow); + + if (!(flags & no_fill)) { + if (flags & 0x04) { + fill = RCT2_ADDRESS(0x0141FC49, uint8)[0]; + } + gfx_fill_rect(dpi, left+1, top+1, right-1, bottom-1, fill); + } + } + } +} \ No newline at end of file diff --git a/src/drawing/sprite.c b/src/drawing/sprite.c new file mode 100644 index 0000000000..022a48efaf --- /dev/null +++ b/src/drawing/sprite.c @@ -0,0 +1,577 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John, Peter Hill, Duncan Frost + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of OpenRCT2. + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#include "../addresses.h" +#include "../common.h" +#include "drawing.h" + +typedef struct { + uint32 num_entries; + uint32 total_size; +} rct_g1_header; + +void *_g1Buffer = NULL; + +/** + * + * rct2: 0x00678998 + */ +int gfx_load_g1() +{ + FILE *file; + rct_g1_header header; + unsigned int i; + + rct_g1_element *g1Elements = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element); + + file = fopen(get_file_path(PATH_ID_G1), "rb"); + if (file != NULL) { + if (fread(&header, 8, 1, file) == 1) { + // number of elements is stored in g1.dat, but because the entry headers are static, this can't be variable until + // made into a dynamic array + header.num_entries = 29294; + + // Read element headers + fread(g1Elements, header.num_entries * sizeof(rct_g1_element), 1, file); + + // Read element data + _g1Buffer = rct2_malloc(header.total_size); + fread(_g1Buffer, header.total_size, 1, file); + + fclose(file); + + // Fix entry data offsets + for (i = 0; i < header.num_entries; i++) + g1Elements[i].offset += (int)_g1Buffer; + + // Successful + return 1; + } + fclose(file); + } + + // Unsuccessful + RCT2_ERROR("Unable to load g1.dat"); + return 0; +} + +/** + * Copies a sprite onto the buffer. There is no compression used on the sprite + * image. + * rct2: 0x0067A690 + */ +void gfx_bmp_sprite_to_buffer(uint8* palette_pointer, uint8* unknown_pointer, uint8* source_pointer, uint8* dest_pointer, rct_g1_element* source_image, rct_drawpixelinfo *dest_dpi, int height, int width, int image_type){ + uint8 zoom_level = dest_dpi->zoom_level; + uint8 zoom_amount = 1 << zoom_level; + //Requires use of palette? + if (image_type & IMAGE_TYPE_USE_PALETTE){ + + //Mix with another image?? and colour adjusted + if (unknown_pointer!= NULL){ //Not tested. I can't actually work out when this code runs. + unknown_pointer += source_pointer - source_image->offset;// RCT2_GLOBAL(0x9E3CE0, uint32); + + for (; height > 0; height -= zoom_amount){ + uint8* next_source_pointer = source_pointer + (uint32)(source_image->width * zoom_amount); + uint8* next_unknown_pointer = unknown_pointer + (uint32)(source_image->width * zoom_amount); + uint8* next_dest_pointer = dest_pointer + (dest_dpi->width / zoom_amount) + dest_dpi->pitch; + + for (int no_pixels = width; no_pixels > 0; no_pixels -= zoom_amount, source_pointer += zoom_amount, unknown_pointer += zoom_amount, dest_pointer++){ + uint8 pixel = *source_pointer; + pixel = palette_pointer[pixel]; + pixel &= *unknown_pointer; + if (pixel){ + *dest_pointer = pixel; + } + } + source_pointer = next_source_pointer; + dest_pointer = next_dest_pointer; + unknown_pointer = next_unknown_pointer; + } + return; + } + + //image colour adjusted? + for (; height > 0; height -= zoom_amount){ + uint8* next_source_pointer = source_pointer + (uint32)(source_image->width * zoom_amount); + uint8* next_dest_pointer = dest_pointer + (dest_dpi->width / zoom_amount) + dest_dpi->pitch; + for (int no_pixels = width; no_pixels > 0; no_pixels -= zoom_amount, source_pointer += zoom_amount, dest_pointer++){ + uint8 pixel = *source_pointer; + pixel = palette_pointer[pixel]; + if (pixel){ + *dest_pointer = pixel; + } + } + + source_pointer = next_source_pointer; + dest_pointer = next_dest_pointer; + } + return; + } + + //Mix with background. It only uses source pointer for + //telling if it needs to be drawn not for colour. + if (image_type & IMAGE_TYPE_MIX_BACKGROUND){//Not tested + for (; height > 0; height -= zoom_amount){ + uint8* next_source_pointer = source_pointer + (uint32)(source_image->width * zoom_amount); + uint8* next_dest_pointer = dest_pointer + (dest_dpi->width / zoom_amount) + dest_dpi->pitch; + + for (int no_pixels = width; no_pixels > 0; no_pixels -= zoom_amount, source_pointer += zoom_amount, dest_pointer++){ + uint8 pixel = *source_pointer; + if (pixel){ + pixel = *dest_pointer; + pixel = palette_pointer[pixel]; + *dest_pointer = pixel; + } + } + + source_pointer = next_source_pointer; + dest_pointer = next_dest_pointer; + } + return; + } + + //Basic bitmap no fancy stuff + if (!(source_image->flags & G1_FLAG_BMP)){//Not tested + for (; height > 0; height -= zoom_amount){ + uint8* next_source_pointer = source_pointer + (uint32)(source_image->width * zoom_amount); + uint8* next_dest_pointer = dest_pointer + (dest_dpi->width / zoom_amount) + dest_dpi->pitch; + + for (int no_pixels = width; no_pixels > 0; no_pixels -= zoom_amount, dest_pointer++, source_pointer += zoom_amount){ + *dest_pointer = *source_pointer; + } + + dest_pointer = next_dest_pointer; + source_pointer = next_source_pointer; + } + return; + } + + if (RCT2_GLOBAL(0x9E3CDC, uint32) != 0){//Not tested. I can't actually work out when this code runs. + unknown_pointer += source_pointer - source_image->offset; + + for (; height > 0; height -= zoom_amount){ + uint8* next_source_pointer = source_pointer + (uint32)(source_image->width * zoom_amount); + uint8* next_unknown_pointer = unknown_pointer + (uint32)(source_image->width * zoom_amount); + uint8* next_dest_pointer = dest_pointer + (dest_dpi->width / zoom_amount) + dest_dpi->pitch; + + for (int no_pixels = width; no_pixels > 0; no_pixels -= zoom_amount, dest_pointer++, source_pointer += zoom_amount, unknown_pointer += zoom_amount){ + uint8 pixel = *source_pointer; + pixel &= *unknown_pointer; + if (pixel){ + *dest_pointer = pixel; + } + } + dest_pointer = next_dest_pointer; + source_pointer = next_source_pointer; + unknown_pointer = next_unknown_pointer; + } + } + + //Basic bitmap with no draw pixels + for (; height > 0; height -= zoom_amount){ + uint8* next_source_pointer = source_pointer + (uint32)(source_image->width * zoom_amount); + uint8* next_dest_pointer = dest_pointer + (dest_dpi->width / zoom_amount) + dest_dpi->pitch; + + for (int no_pixels = width; no_pixels > 0; no_pixels -= zoom_amount, dest_pointer++, source_pointer += zoom_amount){ + uint8 pixel = *source_pointer; + if (pixel){ + *dest_pointer = pixel; + } + } + dest_pointer = next_dest_pointer; + source_pointer = next_source_pointer; + } + return; +} + +/** + * Transfers readied images onto buffers + * This function copies the sprite data onto the screen + * rct2: 0x0067AA18 + */ +void gfx_rle_sprite_to_buffer(uint8* source_bits_pointer, uint8* dest_bits_pointer, uint8* palette_pointer, rct_drawpixelinfo *dpi, int image_type, int source_y_start, int height, int source_x_start, int width){ + int zoom_level = dpi->zoom_level; + int zoom_amount = 1 << zoom_level; + uint8* next_source_pointer; + uint8* next_dest_pointer = dest_bits_pointer; + + //For every line in the image + for (int y = source_y_start; y < (height + source_y_start); y += zoom_amount){ + + //The first part of the source pointer is a list of offsets to different lines + //This will move the pointer to the correct source line. + next_source_pointer = source_bits_pointer + ((uint16*)source_bits_pointer)[y]; + + uint8 last_data_line = 0; + + //For every data section in the line + while (!last_data_line){ + uint8* source_pointer = next_source_pointer; + uint8* dest_pointer = next_dest_pointer; + + int no_pixels = *source_pointer++; + //gap_size is the number of non drawn pixels you require to + //jump over on your destination + uint8 gap_size = *source_pointer++; + //The last bit in no_pixels tells you if you have reached the end of a line + last_data_line = no_pixels & 0x80; + //Clear the last data line bit so we have just the no_pixels + no_pixels &= 0x7f; + //Have our next source pointer point to the next data section + next_source_pointer = source_pointer + no_pixels; + + //Calculates the start point of the image + int x_start = gap_size - source_x_start; + + if (x_start > 0){ + //Since the start is positive + //We need to move the drawing surface to the correct position + dest_pointer += x_start / zoom_amount; + } + else{ + //If the start is negative we require to remove part of the image. + //This is done by moving the image pointer to the correct position. + source_pointer -= x_start; + //The no_pixels will be reduced in this operation + no_pixels += x_start; + //If there are no pixels there is nothing to draw this data section + if (no_pixels <= 0) continue; + //Reset the start position to zero as we have taken into account all moves + x_start = 0; + } + + int x_end = x_start + no_pixels; + //If the end position is further out than the whole image + //end position then we need to shorten the line again + if (x_end > width){ + //Shorten the line + no_pixels -= x_end - width; + //If there are no pixels there is nothing to draw. + if (no_pixels <= 0) continue; + } + + //Finally after all those checks, copy the image onto the drawing surface + //If the image type is not a basic one we require to mix the pixels + if (image_type & IMAGE_TYPE_USE_PALETTE){//In the .exe these are all unraveled loops + for (; no_pixels > 0; no_pixels -= zoom_amount, source_pointer += zoom_amount, dest_pointer++){ + uint8 al = *source_pointer; + uint8 ah = *dest_pointer; + if (image_type & IMAGE_TYPE_MIX_BACKGROUND) + al = palette_pointer[(((uint16)al << 8) | ah) - 0x100]; + else + al = palette_pointer[al]; + *dest_pointer = al; + } + } + else if (image_type & IMAGE_TYPE_MIX_BACKGROUND){//In the .exe these are all unraveled loops + //Doesnt use source pointer ??? mix with background only? + //Not Tested + + for (; no_pixels > 0; no_pixels -= zoom_amount, dest_pointer++){ + uint8 pixel = *dest_pointer; + pixel = palette_pointer[pixel]; + *dest_pointer = pixel; + } + } + else + { + for (; no_pixels > 0; no_pixels -= zoom_amount, source_pointer += zoom_amount, dest_pointer++){ + *dest_pointer = *source_pointer; + } + } + } + + //Add a line to the drawing surface pointer + next_dest_pointer += dpi->width / zoom_amount + dpi->pitch; + } +} + +/** + * + * rct2: 0x0067A28E + * image_id (ebx) + * image_id as below + * 0b_111X_XXXX_XXXX_XXXX_XXXX_XXXX_XXXX_XXXX image_type + * 0b_XXX1_11XX_XXXX_XXXX_XXXX_XXXX_XXXX_XXXX image_sub_type (unknown pointer) + * 0b_XXX1_1111_XXXX_XXXX_XXXX_XXXX_XXXX_XXXX secondary_colour + * 0b_XXXX_XXXX_1111_1XXX_XXXX_XXXX_XXXX_XXXX primary_colour + * 0b_XXXX_X111_1111_1XXX_XXXX_XXXX_XXXX_XXXX palette_ref + * 0b_XXXX_XXXX_XXXX_X111_1111_1111_1111_1111 image_id (offset to g1) + * x (cx) + * y (dx) + * dpi (esi) + * tertiary_colour (ebp) + */ +void gfx_draw_sprite(rct_drawpixelinfo *dpi, int image_id, int x, int y, uint32 tertiary_colour) +{ + //RCT2_CALLPROC_X(0x0067A28E, 0, image_id, x, y, 0, (int)dpi, tertiary_colour); + //return; + + int image_type = (image_id & 0xE0000000) >> 28; + int image_sub_type = (image_id & 0x1C000000) >> 26; + + uint8* palette_pointer = NULL; + uint8 palette[0x100]; + + RCT2_GLOBAL(0x00EDF81C, uint32) = image_id & 0xE0000000; + + uint8* unknown_pointer = (uint8*)(RCT2_ADDRESS(0x9E3CE4, uint32*)[image_sub_type]); + RCT2_GLOBAL(0x009E3CDC, uint32) = (uint32)unknown_pointer; + + if (image_type && !(image_type & IMAGE_TYPE_UNKNOWN)) { + uint8 palette_ref = (image_id >> 19) & 0xFF; + if (image_type & IMAGE_TYPE_MIX_BACKGROUND){ + unknown_pointer = NULL; + RCT2_GLOBAL(0x009E3CDC, uint32) = 0; + } + else{ + palette_ref &= 0x7F; + } + + uint16 palette_offset = palette_to_g1_offset[palette_ref]; + palette_pointer = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[palette_offset].offset; + RCT2_GLOBAL(0x9ABDA4, uint32) = (uint32)palette_pointer; + } + else if (image_type && !(image_type & IMAGE_TYPE_USE_PALETTE)){ + RCT2_GLOBAL(0x9E3CDC, uint32) = 0; + unknown_pointer = NULL; + + uint32 primary_offset = palette_to_g1_offset[(image_id >> 19) & 0x1F]; + uint32 secondary_offset = palette_to_g1_offset[(image_id >> 24) & 0x1F]; + uint32 tertiary_offset = palette_to_g1_offset[tertiary_colour]; + + rct_g1_element* primary_colour = &RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[primary_offset]; + rct_g1_element* secondary_colour = &RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[secondary_offset]; + rct_g1_element* tertiary_colour = &RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[tertiary_offset]; + + memcpy((uint8*)0x9ABFFF, &primary_colour->offset[0xF3], 12); + memcpy((uint8*)0x9ABFD6, &secondary_colour->offset[0xF3], 12); + memcpy((uint8*)0x9ABF3A, &tertiary_colour->offset[0xF3], 12); + + //image_id + RCT2_GLOBAL(0xEDF81C, uint32) |= 0x20000000; + image_id |= IMAGE_TYPE_USE_PALETTE << 28; + + RCT2_GLOBAL(0x9ABDA4, uint32) = 0x9ABF0C; + palette_pointer = (uint8*)0x9ABF0C; + } + else if (image_type){ + RCT2_GLOBAL(0x9E3CDC, uint32) = 0; + unknown_pointer = NULL; + //Copy the peep palette into a new palette. + //Not really required but its nice to make a copy + memcpy(palette, peep_palette, 0x100); + + //Top + int top_type = (image_id >> 19) & 0x1f; + uint32 top_offset = palette_to_g1_offset[top_type]; //RCT2_ADDRESS(0x97FCBC, uint32)[top_type]; + rct_g1_element top_palette = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[top_offset]; + memcpy(palette + 0xF3, top_palette.offset + 0xF3, 12); + + //Trousers + int trouser_type = (image_id >> 24) & 0x1f; + uint32 trouser_offset = palette_to_g1_offset[trouser_type]; //RCT2_ADDRESS(0x97FCBC, uint32)[trouser_type]; + rct_g1_element trouser_palette = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[trouser_offset]; + memcpy(palette + 0xCA, trouser_palette.offset + 0xF3, 12); + + //For backwards compatibility until the zooming function is done + RCT2_GLOBAL(0x9ABDA4, uint8*) = palette; + palette_pointer = palette; + } + gfx_draw_sprite_palette_set(dpi, image_id, x, y, palette_pointer, unknown_pointer); +} + +/* +* rct: 0x0067A46E +* image_id (ebx) and also (0x00EDF81C) +* palette_pointer (0x9ABDA4) +* unknown_pointer (0x9E3CDC) +* dpi (edi) +* x (cx) +* y (dx) +*/ +void gfx_draw_sprite_palette_set(rct_drawpixelinfo *dpi, int image_id, int x, int y, uint8* palette_pointer, uint8* unknown_pointer){ + int image_element = 0x7FFFF&image_id; + int image_type = (image_id & 0xE0000000) >> 28; + + rct_g1_element* g1_source = &(RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[image_element]); + + //Zooming code has been integrated into main code. + //if (dpi->zoom_level >= 1){ //These have not been tested + // //something to do with zooming + // if (dpi->zoom_level == 1){ + // RCT2_CALLPROC_X(0x0067A28E, 0, image_id, x, y, 0, (int)dpi, 0); + // return; + // } + // if (dpi->zoom_level == 2){ + // RCT2_CALLPROC_X(0x0067DADA, 0, (int)g1_source, x, y, 0, (int)dpi, 0); + // return; + // } + // RCT2_CALLPROC_X(0x0067FAAE, 0, (int)g1_source, x, y, 0, (int)dpi, 0); + // return; + //} + if ( dpi->zoom_level && (g1_source->flags & (1<<4)) ){ + rct_drawpixelinfo zoomed_dpi = { + .bits = dpi->bits, + .x = dpi->x >> 1, + .y = dpi->y >> 1, + .height = dpi->height>>1, + .width = dpi->width>>1, + .pitch = dpi->pitch, + .zoom_level = dpi->zoom_level - 1 + }; + gfx_draw_sprite_palette_set(&zoomed_dpi, (image_type << 28) | (image_element - g1_source->zoomed_offset), x >> 1, y >> 1, palette_pointer, unknown_pointer); + return; + } + + if ( dpi->zoom_level && (g1_source->flags & (1<<5)) ){ + return; + } + + //Its used super often so we will define it to a seperate variable. + int zoom_level = dpi->zoom_level; + int zoom_amount = 1 << zoom_level; + int zoom_mask = 0xFFFFFFFF << zoom_level; + + //This will be the height of the drawn image + int height = g1_source->height; + //This is the start y coordinate on the destination + sint16 dest_start_y = ((y + g1_source->y_offset)&zoom_mask) - dpi->y; + //This is the start y coordinate on the source + int source_start_y = 0; + + if (dest_start_y < 0){ + //If the destination y is negative reduce the height of the + //image as we will cut off the bottom + height += dest_start_y; + //If the image is no longer visible nothing to draw + if (height <= 0){ + return; + } + //The source image will start a further up the image + source_start_y -= dest_start_y; + //The destination start is now reset to 0 + dest_start_y = 0; + } + + int dest_end_y = dest_start_y + height; + + if (dest_end_y > dpi->height){ + //If the destination y is outside of the drawing + //image reduce the height of the image + height -= dest_end_y - dpi->height; + } + //If the image no longer has anything to draw + if (height <= 0)return; + + dest_start_y /= zoom_amount; + dest_end_y /= zoom_amount; + + //This will be the width of the drawn image + int width = g1_source->width; + //This is the source start x coordinate + int source_start_x = 0; + //This is the destination start x coordinate + sint16 dest_start_x = ((x + g1_source->x_offset) & zoom_mask) - dpi->x; + + if (dest_start_x < 0){ + //If the destination is negative reduce the width + //image will cut off the side + width += dest_start_x; + //If there is no image to draw + if (width <= 0){ + return; + } + //The source start will also need to cut off the side + source_start_x -= dest_start_x; + //Reset the destination to 0 + dest_start_x = 0; + } + + int dest_end_x = dest_start_x + width; + + if (dest_end_x > dpi->width){ + //If the destination x is outside of the drawing area + //reduce the image width. + width -= dest_end_x - dpi->width; + //If there is no image to draw. + if (width <= 0)return; + } + + dest_start_x /= zoom_amount; + dest_end_x /= zoom_amount; + + uint8* dest_pointer = (uint8*)dpi->bits; + //Move the pointer to the start point of the destination + dest_pointer += ((dpi->width / zoom_amount) + dpi->pitch)*dest_start_y + dest_start_x; + + if (g1_source->flags & G1_FLAG_RLE_COMPRESSION){ + //We have to use a different method to move the source pointer for + //rle encoded sprites so that will be handled within this function + gfx_rle_sprite_to_buffer(g1_source->offset, dest_pointer, palette_pointer, dpi, image_type, source_start_y, height, source_start_x, width); + return; + } + uint8* source_pointer = g1_source->offset; + //Move the pointer to the start point of the source + source_pointer += g1_source->width*source_start_y + source_start_x; + + if (!(g1_source->flags & 0x02)){ + gfx_bmp_sprite_to_buffer(palette_pointer, unknown_pointer, source_pointer, dest_pointer, g1_source, dpi, height, width, image_type); + return; + } + //0x67A60A Not tested + int total_no_pixels = g1_source->width*g1_source->height; + source_pointer = g1_source->offset; + uint8* new_source_pointer_start = malloc(total_no_pixels); + uint8* new_source_pointer = new_source_pointer_start;// 0x9E3D28; + int ebx, ecx; + while (total_no_pixels>0){ + sint8 no_pixels = *source_pointer; + if (no_pixels >= 0){ + source_pointer++; + total_no_pixels -= no_pixels; + memcpy((char*)new_source_pointer, (char*)source_pointer, no_pixels); + new_source_pointer += no_pixels; + source_pointer += no_pixels; + continue; + } + ecx = no_pixels; + no_pixels &= 0x7; + ecx >>= 3;//SAR + int eax = ((int)no_pixels)<<8; + ecx = -ecx;//Odd + eax = eax & 0xFF00 + *(source_pointer+1); + total_no_pixels -= ecx; + source_pointer += 2; + ebx = (uint32)new_source_pointer - eax; + eax = (uint32)source_pointer; + source_pointer = (uint8*)ebx; + ebx = eax; + eax = 0; + memcpy((char*)new_source_pointer, (char*)source_pointer, ecx); + new_source_pointer += ecx; + source_pointer += ecx; + source_pointer = (uint8*)ebx; + } + source_pointer = new_source_pointer_start + g1_source->width*source_start_y + source_start_x; + gfx_bmp_sprite_to_buffer(palette_pointer, unknown_pointer, source_pointer, dest_pointer, g1_source, dpi, height, width, image_type); + free(new_source_pointer_start); + return; +} \ No newline at end of file diff --git a/src/drawing/string.c b/src/drawing/string.c new file mode 100644 index 0000000000..2bfbfc8753 --- /dev/null +++ b/src/drawing/string.c @@ -0,0 +1,1041 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John, Peter Hill, Duncan Frost + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of OpenRCT2. + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#include "../addresses.h" +#include "../localisation/localisation.h" +#include "../sprites.h" +#include "drawing.h" + +/** + * + * rct2: 0x006C19AC + */ +void gfx_load_character_widths(){ + + uint8* char_width_pointer = RCT2_ADDRESS(RCT2_ADDRESS_FONT_CHAR_WIDTH, uint8); + for (int char_set_offset = 0; char_set_offset < 4*0xE0; char_set_offset+=0xE0){ + for (uint8 c = 0; c < 0xE0; c++, char_width_pointer++){ + rct_g1_element g1 = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[c + SPR_CHAR_START + char_set_offset]; + int width; + + if (char_set_offset == 0xE0*3) width = g1.width + 1; + else width = g1.width - 1; + + if (c >= (FORMAT_ARGUMENT_CODE_START - 0x20) && c < (FORMAT_COLOUR_CODE_END - 0x20)){ + width = 0; + } + *char_width_pointer = (uint8)width; + } + + } + + uint8 drawing_surface[0x40]; + rct_drawpixelinfo dpi = { + .bits = (char*)&drawing_surface, + .width = 8, + .height = 8, + .x = 0, + .y = 0, + .pitch = 0, + .zoom_level = 0}; + + + for (int i = 0; i < 0xE0; ++i){ + memset(drawing_surface, 0, sizeof(drawing_surface)); + gfx_draw_sprite(&dpi, i + 0x10D5, -1, 0, 0); + + for (int x = 0; x < 8; ++x){ + uint8 val = 0; + for (int y = 0; y < 8; ++y){ + val >>= 1; + if (dpi.bits[x + y * 8]==1){ + val |= 0x80; + } + } + RCT2_ADDRESS(0xF4393C, uint8)[i * 8 + x] = val; + } + + } + + for (int i = 0; i < 0x20; ++i){ + rct_g1_element* g1 = &(RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[0x606 + i]); + uint8* unknown_pointer = RCT2_ADDRESS(0x9C3852, uint8) + 0xa12 * i; + g1->offset = unknown_pointer; + g1->width = 0x40; + g1->height = 0x28; + *((uint16*)unknown_pointer) = 0xFFFF; + *((uint32*)(unknown_pointer + 0x0E)) = 0; + } +} + +/** + * Return the width of the string in buffer + * + * rct2: 0x006C2321 + * buffer (esi) + */ +int gfx_get_string_width(char* buffer) +{ + // Current font sprites + uint16* current_font_sprite_base; + // Width of string + int width; + rct_g1_element g1_element; + + current_font_sprite_base = RCT2_ADDRESS(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16); + width = 0; + + for (uint8* curr_char = (uint8*)buffer; *curr_char != (uint8)0; curr_char++) { + + if (*curr_char >= 0x20) { + width += RCT2_ADDRESS(RCT2_ADDRESS_FONT_CHAR_WIDTH, uint8)[*current_font_sprite_base + (*curr_char - 0x20)]; + continue; + } + switch(*curr_char) { + case FORMAT_MOVE_X: + curr_char++; + width = *curr_char; + break; + case FORMAT_ADJUST_PALETTE: + case 3: + case 4: + curr_char++; + break; + case FORMAT_NEWLINE: + case FORMAT_NEWLINE_SMALLER: + continue; + case FORMAT_TINYFONT: + *current_font_sprite_base = 0x1C0; + break; + case FORMAT_BIGFONT: + *current_font_sprite_base = 0x2A0; + break; + case FORMAT_MEDIUMFONT: + *current_font_sprite_base = 0x0E0; + break; + case FORMAT_SMALLFONT: + *current_font_sprite_base = 0; + break; + case FORMAT_OUTLINE: + case FORMAT_OUTLINE_OFF: + case FORMAT_WINDOW_COLOUR_1: + case FORMAT_WINDOW_COLOUR_2: + case FORMAT_WINDOW_COLOUR_3: + case 0x10: + continue; + case FORMAT_INLINE_SPRITE: + g1_element = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[*((uint32*)(curr_char+1))&0x7FFFF]; + width += g1_element.width; + curr_char += 4; + break; + default: + if (*curr_char <= 0x16) { //case 0x11? FORMAT_NEW_LINE_X_Y + curr_char += 2; + continue; + } + curr_char += 4;//never happens? + break; + } + } + return width; +} + +/** + * Clip the text in buffer to width, add ellipsis and return the new width of the clipped string + * + * rct2: 0x006C2460 + * buffer (esi) + * width (edi) + */ +int gfx_clip_string(char* buffer, int width) +{ + // Location of font sprites + uint16 current_font_sprite_base; + // Width the string has to fit into + unsigned int max_width; + // Character to change to ellipsis + unsigned char* last_char; + // Width of the string, including ellipsis + + unsigned int clipped_width; + + rct_g1_element g1_element; + + if (width < 6) { + *buffer = 0; + return 0; + } + + current_font_sprite_base = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16); + max_width = width - (3 * RCT2_ADDRESS(0x141E9F6, uint8)[current_font_sprite_base]); + + clipped_width = 0; + last_char = buffer; + + for (unsigned char* curr_char = buffer; *curr_char != (uint8)0; curr_char++) { + if (*curr_char < 0x20) { + switch (*curr_char) { + case FORMAT_MOVE_X: + curr_char++; + clipped_width = *curr_char; + continue; + case FORMAT_ADJUST_PALETTE: + case 3: + case 4: + curr_char++; + continue; + case FORMAT_NEWLINE: + case FORMAT_NEWLINE_SMALLER: + continue; + case FORMAT_TINYFONT: + current_font_sprite_base = 0x1C0; + break; + case FORMAT_BIGFONT: + current_font_sprite_base = 0x2A0; + break; + case FORMAT_MEDIUMFONT: + current_font_sprite_base = 0x0E0; + break; + case FORMAT_SMALLFONT: + current_font_sprite_base = 0; + break; + case FORMAT_OUTLINE: + case FORMAT_OUTLINE_OFF: + case FORMAT_WINDOW_COLOUR_1: + case FORMAT_WINDOW_COLOUR_2: + case FORMAT_WINDOW_COLOUR_3: + case 0x10: + continue; + case FORMAT_INLINE_SPRITE: + g1_element = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[*((uint32*)(curr_char+1))&0x7FFFF]; + clipped_width += g1_element.width; + curr_char += 4; + continue; + default: + if (*curr_char <= 0x16) { //case 0x11? FORMAT_NEW_LINE_X_Y + curr_char += 2; + continue; + } + curr_char += 4;//never happens? + continue; + } + max_width = width - (3 * RCT2_ADDRESS(0x141E9F6, uint8)[current_font_sprite_base]); + } + + clipped_width += RCT2_ADDRESS(RCT2_ADDRESS_FONT_CHAR_WIDTH, uint8)[current_font_sprite_base + (*curr_char - 0x20)]; + + if ((int)clipped_width > width) { +// *((uint32*)last_char) = '...'; + strcpy(last_char-3, "..."); + clipped_width = width; + return clipped_width; + } + if (clipped_width <= max_width) { + last_char = curr_char+1; + } + } + return clipped_width; +} + + +/** + * Wrap the text in buffer to width, returns width of longest line. + * + * Inserts NULL where line should break (as \n is used for something else), + * so the number of lines is returned in num_lines. font_height seems to be + * a control character for line height. + * + * rct2: 0x006C21E2 + * buffer (esi) + * width (edi) - in + * num_lines (edi) - out + * font_height (ebx) - out + */ +int gfx_wrap_string(char* buffer, int width, int* num_lines, int* font_height) +{ + unsigned int line_width = 0; + unsigned int max_width = 0; + rct_g1_element g1_element; + + *num_lines = 0; + *font_height = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16); + + // Pointer to the start of the current word + unsigned char* curr_word = NULL; + // Width of line up to current word + unsigned int curr_width; + + for (unsigned char* curr_char = buffer; *curr_char != (uint8)0; curr_char++) { + + // Remember start of current word and line width up to this word + if (*curr_char == ' ') { + curr_word = curr_char; + curr_width = line_width; + } + + // 5 is RCT2 new line? + if (*curr_char != 5) { + if (*curr_char < ' ') { + switch(*curr_char) { + case FORMAT_MOVE_X: + case FORMAT_ADJUST_PALETTE: + case 3: + case 4: + curr_char++; + continue; + case FORMAT_NEWLINE: + case FORMAT_NEWLINE_SMALLER: + continue; + case FORMAT_TINYFONT: + *font_height = 0x1C0; + continue; + case FORMAT_BIGFONT: + *font_height = 0x2A0; + continue; + case FORMAT_MEDIUMFONT: + *font_height = 0xE0; + continue; + case FORMAT_SMALLFONT: + *font_height = 0; + continue; + case FORMAT_OUTLINE: + case FORMAT_OUTLINE_OFF: + case FORMAT_WINDOW_COLOUR_1: + case FORMAT_WINDOW_COLOUR_2: + case FORMAT_WINDOW_COLOUR_3: + case 0x10: + continue; + case FORMAT_INLINE_SPRITE: + g1_element = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[*((uint32*)(curr_char + 1)) & 0x7FFFF]; + line_width += g1_element.width; + curr_char += 4; + break; + default: + if (*curr_char <= 0x16) { + curr_char += 2; + continue; + } + curr_char += 4; + continue; + } + } + + line_width += RCT2_ADDRESS(RCT2_ADDRESS_FONT_CHAR_WIDTH, uint8)[*font_height + (*curr_char - 0x20)]; + + if ((int)line_width <= width) { + continue; + } + if (curr_word == 0) { + curr_char--; + unsigned char* old_char = curr_char; + unsigned char swap_char = 0; + unsigned char temp; + // Insert NULL at current character + // Aboslutely no guarantee that this won't overrun! + do { + temp = swap_char; + swap_char = *curr_char; + *curr_char = temp; + curr_char++; + } while(swap_char != 0); + + *curr_char = swap_char; + curr_char = old_char; + curr_char++; + *num_lines += 1; + + if (line_width > max_width) { + max_width = line_width; + } + line_width = 0; + curr_word = 0; + continue; + } + curr_char = curr_word; + line_width = curr_width; + } + + *num_lines += 1; + *curr_char = 0; + + if (line_width > max_width) { + max_width = line_width; + } + line_width = 0; + curr_word = 0; + } + if (max_width == 0)return line_width; + return max_width; +} + + +/** + * Draws i formatted text string left aligned at i specified position but clips + * the text with an elipsis if the text width exceeds the specified width. + * rct2: 0x006C1B83 + * dpi (edi) + * format (bx) + * args (esi) + * colour (al) + * x (cx) + * y (dx) + * width (bp) + */ +void gfx_draw_string_left_clipped(rct_drawpixelinfo* dpi, int format, void* args, int colour, int x, int y, int width) +{ + char* buffer; + + buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char); + format_string(buffer, format, args); + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 0xE0; + + // Clip text - return value is not needed + gfx_clip_string(buffer, width); + + gfx_draw_string(dpi, buffer, colour, x, y); +} + +/** + * Draws i formatted text string centred at i specified position but clips the + * text with an elipsis if the text width exceeds the specified width. + * rct2: 0x006C1BBA + * dpi (edi) + * format (bx) + * args (esi) + * colour (al) + * x (cx) + * y (dx) + * width (bp) + */ +void gfx_draw_string_centred_clipped(rct_drawpixelinfo *dpi, int format, void *args, int colour, int x, int y, int width) +{ + char* buffer; + short text_width; + + buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char); + format_string(buffer, format, args); + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 0xE0; + + // Clip text + text_width = gfx_clip_string(buffer, width); + + // Draw the text centred + if (text_width <= 0xFFFF) { + x -= (text_width - 1) / 2; + gfx_draw_string(dpi, buffer, colour, x, y); + } +} + +/** + * Draws i formatted text string right aligned. + * rct2: 0x006C1BFC + * dpi (edi) + * format (bx) + * args (esi) + * colour (al) + * x (cx) + * y (dx) + */ +void gfx_draw_string_right(rct_drawpixelinfo* dpi, int format, void* args, int colour, int x, int y) +{ + char* buffer; + short text_width; + + buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char); + format_string(buffer, format, args); + + // Measure text width + text_width = gfx_get_string_width(buffer); + + // Draw the text right aligned + x -= text_width; + gfx_draw_string(dpi, buffer, colour, x, y); +} + +/** + * Draws i formatted text string centred at i specified position. + * rct2: 0x006C1D6C + * dpi (edi) + * format (bx) + * x (cx) + * y (dx) + * colour (al) + * args (esi) + */ +void gfx_draw_string_centred(rct_drawpixelinfo *dpi, int format, int x, int y, int colour, void *args) +{ + char* buffer; + short text_width; + + buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char); + format_string(buffer, format, args); + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 0xE0; + + // Measure text width + text_width = gfx_get_string_width(buffer); + + // Draw the text centred + if (text_width <= 0xFFFF) { + x -= text_width / 2; + gfx_draw_string(dpi, buffer, colour, x, y); + } +} + +/** + * + * rct2: 0x006C1E53 + * dpi (edi) + * args (esi) + * x (cx) + * y (dx) + * width (bp) + * colour (al) + * format (ebx) + */ +int gfx_draw_string_centred_wrapped(rct_drawpixelinfo *dpi, void *args, int x, int y, int width, int format, int colour) +{ + int font_height, line_height, line_width, line_y, num_lines; + // Location of font sprites + uint16* current_font_sprite_base; + + char* buffer = RCT2_ADDRESS(0x009C383D, char); + + current_font_sprite_base = RCT2_ADDRESS(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16); + *current_font_sprite_base = 0xE0; + + gfx_draw_string(dpi, buffer, colour, dpi->x, dpi->y); + + buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char); + + format_string(buffer, format, args); + + *current_font_sprite_base = 0xE0; + + // line_width unused here + line_width = gfx_wrap_string(buffer, width, &num_lines, &font_height); + + line_height = 0x0A; + + if (font_height > 0xE0) { + line_height = 6; + if (font_height != 0x1C0) { + line_height = 0x12; + } + } + + if (*buffer == 0x0B) { + line_height = line_height + 1; + } + + font_height = (line_height / 2) * num_lines; + line_y = y - font_height; + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_FLAGS, uint16) = 0; + + for (int line = 0; line <= num_lines; ++line) { + int half_width = gfx_get_string_width(buffer) / 2; + gfx_draw_string(dpi, buffer, 0xFE, x - half_width, line_y); + + buffer += get_string_length(buffer) + 1; + line_y += line_height; + } + + return line_y - y; +} + +/** + * + * rct2: 0x006C2105 + * dpi (edi) + * args (esi) + * x (cx) + * y (dx) + * width (bp) + * format (bx) + * colour (al) + */ +int gfx_draw_string_left_wrapped(rct_drawpixelinfo *dpi, void *args, int x, int y, int width, int format, int colour) +{ + // font height might actually be something else + int font_height, line_height, line_width, line_y, num_lines; + + // Location of font sprites + uint16* current_font_sprite_base = RCT2_ADDRESS(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16); + *current_font_sprite_base = 0xE0; + + char* buffer = RCT2_ADDRESS(0x009C383D, char); + + gfx_draw_string(dpi, buffer, colour, dpi->x, dpi->y); + + buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char); + + format_string(buffer, format, args); + + *current_font_sprite_base = 0xE0; + + // Line width unused here + line_width = gfx_wrap_string(buffer, width, &num_lines, &font_height); + + line_height = 0x0A; + + if (font_height > 0xE0) { + line_height = 6; + if (font_height != 0x1C0) { + line_height = 0x12; + } + } + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_FLAGS, uint16) = 0; + + line_y = y; + + for (int line = 0; line <= num_lines; ++line) { + gfx_draw_string(dpi, buffer, 0xFE, x, line_y); + buffer += get_string_length(buffer) + 1; + line_y += line_height; + } + + return line_y - y; +} + +/** + * Draws i formatted text string. + * rct2: 0x006C1B2F + * dpi (edi) + * format (bx) + * args (esi) + * colour (al) + * x (cx) + * y (dx) + */ +void gfx_draw_string_left(rct_drawpixelinfo *dpi, int format, void *args, int colour, int x, int y) +{ + char* buffer; + + buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char); + format_string(buffer, format, args); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 0xE0; + gfx_draw_string(dpi, buffer, colour, x, y); +} + +/** + * Changes the palette so that the next character changes colour + */ +void colour_char(uint8 colour, uint16* current_font_flags, uint8* palette_pointer) { + + int eax; + + rct_g1_element g1_element = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[0x1332]; + eax = ((uint32*)g1_element.offset)[colour & 0xFF]; + + if (!(*current_font_flags & 2)) { + eax = eax & 0x0FF0000FF; + } + // Adjust text palette. Store current colour? + palette_pointer[1] = eax & 0xFF; + palette_pointer[2] = (eax >> 8) & 0xFF; + palette_pointer[3] = (eax >> 16) & 0xFF; + palette_pointer[4] = (eax >> 24) & 0xFF; + RCT2_GLOBAL(0x009ABDA4, uint32) = (uint32)palette_pointer; +} + +/** + * Changes the palette so that the next character changes colour + * This is specific to changing to a predefined window related colour + */ +void colour_char_window(uint8 colour, uint16* current_font_flags,uint8* palette_pointer) { + + int eax; + + eax = RCT2_ADDRESS(0x0141FD45, uint8)[colour * 8]; + if (*current_font_flags & 2) { + eax |= 0x0A0A00; + } + //Adjust text palette. Store current colour? + palette_pointer[1] = eax & 0xFF; + palette_pointer[2] = (eax >> 8) & 0xFF; + palette_pointer[3] = (eax >> 16) & 0xFF; + palette_pointer[4] = (eax >> 24) & 0xFF; + RCT2_GLOBAL(0x009ABDA4, uint32) = (uint32)palette_pointer; +} + + +/** + * + * rct2: 0x00682702 + * dpi (edi) + * buffer (esi) + * colour (al) + * x (cx) + * y (dx) + */ +void gfx_draw_string(rct_drawpixelinfo *dpi, char *buffer, int colour, int x, int y) +{ + + int eax, ebx, ebp; + rct_g1_element* g1_element; + + // Maximum length/height of string + int max_x = x; + int max_y = y; + + // + uint16* current_font_flags = RCT2_ADDRESS(RCT2_ADDRESS_CURRENT_FONT_FLAGS, uint16); + uint16* current_font_sprite_base = RCT2_ADDRESS(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16); + + uint8* palette_pointer = text_palette; + + // Flag for skipping non-printing characters + int skip_char = 0; + + if (colour != 0xFE) { + + if (x >= dpi->x + dpi->width) + return; + + if (x + 0x280 <= dpi->x) + return; + + if (y >= dpi->y + dpi->height) + return; + + if (y + 0x5A <= dpi->y) { + return; + } + + if (colour != 0xFF) { + + // switch_colour: + *current_font_flags = 0; + if (*current_font_sprite_base < 0) { + *current_font_flags |= 4; + if (*current_font_sprite_base != 0xFFFF) { + *current_font_flags |= 8; + } + *current_font_sprite_base = 0xE0; + } + if (colour & (1 << 5)) { + *current_font_flags |= 2; + } + colour &= ~(1 << 5); + + if (!(colour & 0x40)) { + ebp = colour; + if (*current_font_flags & 1) { + if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { + skip_char = 1; + } else { + skip_char = 0; + } + } else { + colour_char_window(ebp, current_font_flags, palette_pointer); + } + } else { + *current_font_flags |= 1; + colour &= 0x1F; + + if (*current_font_flags & 4) { + if (*current_font_flags & 8) { + eax = RCT2_ADDRESS(0x0141FC48, uint8)[colour * 8]; + eax = eax << 16; + eax = eax | RCT2_ADDRESS(0x0141FC46, uint8)[colour * 8]; + } else { + eax = RCT2_ADDRESS(0x0141FC49, uint8)[colour * 8]; + eax = eax << 16; + eax = eax | RCT2_ADDRESS(0x0141FC47, uint8)[colour * 8]; + } + } else { + eax = RCT2_ADDRESS(0x0141FC4A, uint8)[colour * 8]; + eax = eax << 16; + eax = eax | RCT2_ADDRESS(0x0141FC48, uint8)[colour * 8]; + } + // Adjust text palette. Store current colour? ; + palette_pointer[1] = eax & 0xFF; + palette_pointer[2] = (eax >> 8) & 0xFF; + palette_pointer[3] = (eax >> 16) & 0xFF; + palette_pointer[4] = (eax >> 24) & 0xFF; + RCT2_GLOBAL(0x009ABDA4, uint32) = (uint32)palette_pointer; + eax = 0; + } + } + } + + if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { + skip_char = 1; + } + + for (uint8 al = *buffer; al > 0; ++buffer, al = *buffer) { + + // Skip to the next printing character + if (skip_char) { + if (al < 0x20) { + // Control codes + skip_char = 0; + } else if (al >= FORMAT_COLOUR_CODE_START && al <= FORMAT_COLOUR_CODE_END) { + // Colour codes + if (*current_font_flags == 1) { + if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { + skip_char = 1; + } else { + skip_char = 0; + } + continue; + } + colour_char(al - FORMAT_COLOUR_CODE_START, current_font_flags, palette_pointer); + continue; + } else { + continue; + } + } + + // Control codes + switch (al) { + case FORMAT_MOVE_X://Start New Line at start+buffer x, same y. (Overwrite?) + max_x = x + (uint8)*++buffer; + break; + case FORMAT_ADJUST_PALETTE: + al = *++buffer; + if (*current_font_flags & 1) { + if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { + skip_char = 1; + break; + } + } + + eax = palette_to_g1_offset[al]; //RCT2_ADDRESS(0x097FCBC, uint32)[al * 4]; + g1_element = &(RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[eax]); + ebx = g1_element->offset[0xF9] + (1 << 8); + if (!(*current_font_flags & 2)) { + ebx = ebx & 0xFF; + } + + palette_pointer[1] = ebx & 0xff; + palette_pointer[2] = (ebx >> 8) & 0xff; + //Adjust the text palette + memcpy(palette_pointer + 3, &(g1_element->offset[0xF7]), 2); + memcpy(palette_pointer + 5, &(g1_element->offset[0xFA]), 2); + //Set the palette pointer + RCT2_GLOBAL(0x009ABDA4, uint32) = (uint32)palette_pointer; + + + if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { + skip_char = 1; + } + break; + case FORMAT_NEWLINE://Start New Line at set y lower + max_x = x; + if (*current_font_sprite_base <= 0xE0) { + max_y += 10; + break; + } + else if (*current_font_sprite_base == 0x1C0) { + max_y += 6; + break; + } + max_y += 18; + break; + case FORMAT_NEWLINE_SMALLER://Start New Line at set y lower + max_x = x; + if (*current_font_sprite_base <= 0xE0) { + max_y += 5; + break; + } + else if (*current_font_sprite_base == 0x1C0) { + max_y += 3; + break; + } + max_y += 9; + break; + case FORMAT_TINYFONT: + *current_font_sprite_base = 0x1C0; + break; + case FORMAT_BIGFONT: + *current_font_sprite_base = 0x2A0; + break; + case FORMAT_MEDIUMFONT: + *current_font_sprite_base = 0xE0; + break; + case FORMAT_SMALLFONT: + *current_font_sprite_base = 0; + break; + case FORMAT_OUTLINE: + *current_font_flags |= 2; + break; + case FORMAT_OUTLINE_OFF: + *current_font_flags &= 0x0FFFD; + break; + case FORMAT_WINDOW_COLOUR_1: + ebp = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WINDOW_COLOUR_1, uint8); + if (*current_font_flags & 1) { + if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { + skip_char = 1; + } + else { + skip_char = 0; + } + break; + } + colour_char_window(ebp, current_font_flags, palette_pointer); + break; + case FORMAT_WINDOW_COLOUR_2: + ebp = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WINDOW_COLOUR_2, uint8); + if (*current_font_flags & 1) { + if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { + skip_char = 1; + } + else { + skip_char = 0; + } + break; + } + colour_char_window(ebp, current_font_flags, palette_pointer); + break; + case FORMAT_WINDOW_COLOUR_3: + ebp = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WINDOW_COLOUR_3, uint8); + if (*current_font_flags & 1) { + if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { + skip_char = 1; + } + else { + skip_char = 0; + } + break; + } + colour_char_window(ebp, current_font_flags, palette_pointer); + break; + case FORMAT_NEWLINE_X_Y: //Start new line at specified x,y + max_x = x + *++buffer; + max_y = y + *++buffer; + break; + case FORMAT_INLINE_SPRITE: + buffer += 4; + if (max_x >= dpi->x + dpi->width) { + skip_char = 1; + break; + } + ebx = *((uint16*)(buffer - 3)); + eax = ebx & 0x7FFFF; + g1_element = &(RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[eax]); + + gfx_draw_sprite(dpi, ebx, max_x, max_y, 0); + + max_x = max_x + g1_element->width; + break; + default: + // Colour codes + if ((al >= FORMAT_COLOUR_CODE_START) && (al <= FORMAT_COLOUR_CODE_END)){ + + if (*current_font_flags == 1) { + if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { + skip_char = 1; + } else { + skip_char = 0; + } + continue; + } + colour_char(al - FORMAT_COLOUR_CODE_START, current_font_flags, palette_pointer); + continue; + } + + // Normal Characters + if (max_x >= dpi->x + dpi->width) { + skip_char = 1; + } + if (max_x + 0x1A < dpi->x) { + ebx = al-0x20; + ebx += *current_font_sprite_base; + max_x = max_x + (RCT2_ADDRESS(RCT2_ADDRESS_FONT_CHAR_WIDTH, uint8)[ebx] & 0xFF); + continue; + } + + uint32 char_offset = al - 0x20 + *current_font_sprite_base; + RCT2_GLOBAL(0x00EDF81C, uint32) = (IMAGE_TYPE_USE_PALETTE << 28); + + gfx_draw_sprite_palette_set(dpi, (IMAGE_TYPE_USE_PALETTE << 28) | char_offset + SPR_CHAR_START, max_x, max_y, palette_pointer, NULL); + max_x += (RCT2_ADDRESS(RCT2_ADDRESS_FONT_CHAR_WIDTH, uint8)[char_offset] & 0xFF); + continue; + } + } + + gLastDrawStringX = max_x; + gLastDrawStringY = max_y; +} + +void draw_string_left_underline(rct_drawpixelinfo *dpi, int format, void *args, int colour, int x, int y) +{ + char buffer[128]; + int width; + + format_string(buffer, format, args); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 224; + width = gfx_get_string_width(buffer); + gfx_draw_string(dpi, buffer, colour, x, y); + gfx_fill_rect(dpi, x, y + 11, x + width, y + 11, text_palette[1]); + if (text_palette[2] != 0) + gfx_fill_rect(dpi, x + 1, y + 12, x + width + 1, y + 12, text_palette[2]); +} + +void draw_string_right_underline(rct_drawpixelinfo *dpi, int format, void *args, int colour, int x, int y) +{ + char buffer[128]; + int width; + + format_string(buffer, format, args); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 224; + width = gfx_get_string_width(buffer); + x -= width; + gfx_draw_string(dpi, buffer, colour, x, y); + gfx_fill_rect(dpi, x, y + 11, x + width, y + 11, text_palette[1]); + if (text_palette[2] != 0) + gfx_fill_rect(dpi, x + 1, y + 12, x + width + 1, y + 12, text_palette[2]); +} + +void draw_string_centred_underline(rct_drawpixelinfo *dpi, int format, void *args, int colour, int x, int y) +{ + char buffer[128]; + int width; + + format_string(buffer, format, args); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 224; + width = gfx_get_string_width(buffer); + x -= width / 2; + gfx_draw_string(dpi, buffer, colour, x, y); + gfx_fill_rect(dpi, x, y + 11, x + width, y + 11, text_palette[1]); + if (text_palette[2] != 0) + gfx_fill_rect(dpi, x + 1, y + 12, x + width + 1, y + 12, text_palette[2]); +} + +/** + * + * rct2: 0x006C1DB7 + * + * left : cx + * top : dx + * numLines : bp + * text : esi + * dpi : edi + */ +void draw_string_centred_raw(rct_drawpixelinfo *dpi, int x, int y, int numLines, char *text) +{ + RCT2_CALLPROC_X(0x006C1DB7, 0, 0, x, y, (int)text, (int)dpi, numLines); +} \ No newline at end of file diff --git a/src/editor.c b/src/editor.c index d9f7be568e..dd79fb9723 100644 --- a/src/editor.c +++ b/src/editor.c @@ -19,21 +19,22 @@ *****************************************************************************/ #include "addresses.h" -#include "date.h" +#include "audio/audio.h" +#include "drawing/drawing.h" #include "editor.h" #include "game.h" -#include "gfx.h" -#include "map.h" -#include "news_item.h" +#include "interface/window.h" +#include "interface/viewport.h" +#include "localisation/date.h" +#include "localisation/localisation.h" +#include "management/finance.h" +#include "management/news_item.h" #include "object.h" -#include "park.h" -#include "ride.h" -#include "window.h" -#include "viewport.h" -#include "finance.h" -#include "audio.h" -#include "sprite.h" -#include "string_ids.h" +#include "peep/staff.h" +#include "ride/ride.h" +#include "world/map.h" +#include "world/park.h" +#include "world/sprite.h" static void set_all_land_owned(); @@ -62,7 +63,7 @@ void editor_load() finance_init(); date_reset(); window_guest_list_init_vars_b(); - window_staff_init_vars(); + window_staff_list_init_vars(); RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) = SCREEN_FLAGS_SCENARIO_EDITOR; RCT2_GLOBAL(0x0141F570, uint8) = 0; RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) |= PARK_FLAGS_SHOW_REAL_GUEST_NAMES; @@ -111,7 +112,7 @@ void trackdesigner_load() finance_init(); date_reset(); window_guest_list_init_vars_b(); - window_staff_init_vars(); + window_staff_list_init_vars(); RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) = SCREEN_FLAGS_TRACK_DESIGNER; RCT2_GLOBAL(0x0141F570, uint8) = 0; window_new_ride_init_vars(); @@ -149,7 +150,7 @@ void trackmanager_load() finance_init(); date_reset(); window_guest_list_init_vars_b(); - window_staff_init_vars(); + window_staff_list_init_vars(); RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) = SCREEN_FLAGS_TRACK_MANAGER; RCT2_GLOBAL(0x0141F570, uint8) = 0; window_new_ride_init_vars(); @@ -192,10 +193,11 @@ static void set_all_land_owned() */ void sub_6BD3A4() { for (short i = 0; i < 200; i++) { - RCT2_ADDRESS(0x013CA672, uint8)[i] = 0; + RCT2_ADDRESS(RCT2_ADDRESS_STAFF_MODE_ARRAY, uint8)[i] = STAFF_MODE_NONE; } for (short i = 200; i < 204; i++) { - RCT2_ADDRESS(0x013CA672, uint8)[i] = 1; + RCT2_ADDRESS(RCT2_ADDRESS_STAFF_MODE_ARRAY, uint8)[i] = STAFF_MODE_WALK; } - RCT2_CALLPROC_EBPSAFE(0x006C0C3F); + //RCT2_CALLPROC_EBPSAFE(0x006C0C3F); + sub_6C0C3F(); } diff --git a/src/game.c b/src/game.c index 91b057fa4b..5ec5e6b2d0 100644 --- a/src/game.c +++ b/src/game.c @@ -19,113 +19,36 @@ *****************************************************************************/ #include "addresses.h" -#include "audio.h" -#include "climate.h" +#include "audio/audio.h" #include "config.h" -#include "rct2.h" #include "game.h" -#include "finance.h" #include "input.h" -#include "news_item.h" +#include "localisation/localisation.h" +#include "interface/screenshot.h" +#include "interface/viewport.h" +#include "interface/widget.h" +#include "interface/window.h" +#include "management/finance.h" +#include "management/news_item.h" +#include "management/research.h" #include "object.h" -#include "osinterface.h" -#include "park.h" -#include "peep.h" -#include "sawyercoding.h" +#include "peep/peep.h" +#include "peep/staff.h" +#include "platform/osinterface.h" +#include "ride/ride.h" +#include "ride/vehicle.h" #include "scenario.h" -#include "screenshot.h" -#include "sprite.h" -#include "string_ids.h" #include "title.h" #include "tutorial.h" -#include "vehicle.h" -#include "viewport.h" -#include "widget.h" -#include "window.h" -#include "staff.h" -#include "window_error.h" -#include "window_tooltip.h" - +#include "util/sawyercoding.h" +#include "windows/error.h" +#include "windows/tooltip.h" +#include "world/climate.h" +#include "world/park.h" +#include "world/sprite.h" int gGameSpeed = 1; -typedef void(*draw_rain_func)(int left, int top, int width, int height); - -/** -* -* rct2: 0x00684114 -*/ -void draw_light_rain(int left, int top, int width, int height){ - int x_start = -RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int) + 8; - int y_start = (RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int) * 3) + 7; - y_start = -y_start; - - x_start += left; - y_start += top; - - gfx_draw_rain(left, top, width, height, x_start, y_start); - - x_start = -RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int) + 0x18; - y_start = (RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int) * 4) + 0x0D; - y_start = -y_start; - - x_start += left; - y_start += top; - gfx_draw_rain(left, top, width, height, x_start, y_start); -} - -/** -* -* rct2: 0x0068416D -*/ -void draw_heavy_rain(int left, int top, int width, int height){ - int x_start = -RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int); - int y_start = RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int) * 5; - y_start = -y_start; - - x_start += left; - y_start += top; - - gfx_draw_rain(left, top, width, height, x_start, y_start); - - x_start = -RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int) + 0x10; - y_start = (RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int) * 6) + 5; - y_start = -y_start; - - x_start += left; - y_start += top; - - gfx_draw_rain(left, top, width, height, x_start, y_start); - - x_start = -RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int) + 8; - y_start = (RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int) * 3) + 7; - y_start = -y_start; - - x_start += left; - y_start += top; - - gfx_draw_rain(left, top, width, height, x_start, y_start); - - x_start = -RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int) + 0x18; - y_start = (RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int) * 4) + 0x0D; - y_start = -y_start; - - x_start += left; - y_start += top; - - gfx_draw_rain(left, top, width, height, x_start, y_start); -} - -/** -* -* rct2: 0x009AC058 -*/ -const draw_rain_func draw_rain_function[] = { - NULL, - &draw_light_rain, // Light rain - &draw_heavy_rain // Heavy rain -}; - /** * * rct2: 0x0066B5C0 (part of 0x0066B3E8) @@ -138,148 +61,130 @@ void game_create_windows() RCT2_CALLPROC_EBPSAFE(0x0066B905); } -/** - * - * rct2: 0x006838BD - */ -void update_water_animation() -{ - RCT2_CALLPROC_EBPSAFE(0x006838BD); -} - /** * -* rct2: 0x00684383 +* rct2: 0x006838BD */ -void call_draw_rain_func(rct_window* w, short left, short right, short top, short bottom, uint32 draw_rain_func) +void update_palette_effects() { - rct_viewport* vp = w->viewport; - if (vp == NULL) { - return; - } - - left = max(left, vp->x); - right = min(right, vp->width); - - top = max(top, vp->y); - bottom = min(bottom, vp->height); - - if (left >= right || top >= bottom) { - return; - } - - int width = right - left; - int height = bottom - top; - - draw_rain_function[draw_rain_func](left, top, width, height); -} - -/** -* -* rct2: 0x006842AF -* From 0x00684383 on: split into call_draw_rain_func -*/ -void draw_rain_window(rct_window* original_w, short left, short right, short top, short bottom, uint32 draw_rain_func) -{ - rct_window* newWindow = RCT2_GLOBAL(RCT2_ADDRESS_NEW_WINDOW_PTR, rct_window*); - - rct_window* w = original_w + 1; // Start from second window - for (; ; w++) { - if (w >= newWindow) { - // Loop ended, draw rain for original_w - call_draw_rain_func(original_w, left, right, top, bottom, draw_rain_func); - return; + if (RCT2_GLOBAL(RCT2_ADDRESS_LIGHTNING_ACTIVE, uint8) == 1) { + // change palette to lighter color during lightning + int palette = 1532; + if (RCT2_GLOBAL(0x009ADAE0, sint32) != -1) { + palette = RCT2_GLOBAL(RCT2_GLOBAL(0x009ADAE0, int) + 2, int); + } + rct_g1_element g1_element = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[palette]; + int xoffset = g1_element.x_offset; + xoffset = xoffset * 4; + for (int i = 0; i < g1_element.width; i++) { + RCT2_ADDRESS(0x01424680 + xoffset, uint8)[(i * 4) + 0] = -((0xFF - g1_element.offset[(i * 3) + 0]) / 2) - 1; + RCT2_ADDRESS(0x01424680 + xoffset, uint8)[(i * 4) + 1] = -((0xFF - g1_element.offset[(i * 3) + 1]) / 2) - 1; + RCT2_ADDRESS(0x01424680 + xoffset, uint8)[(i * 4) + 2] = -((0xFF - g1_element.offset[(i * 3) + 2]) / 2) - 1; + } + RCT2_GLOBAL(0x014241BC, uint32) = 2; + osinterface_update_palette(RCT2_ADDRESS(0x01424680, uint8), 10, 236); + RCT2_GLOBAL(0x014241BC, uint32) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_LIGHTNING_ACTIVE, uint8)++; + } else { + if (RCT2_GLOBAL(RCT2_ADDRESS_LIGHTNING_ACTIVE, uint8) == 2) { + // change palette back to normal after lightning + int palette = 1532; + if (RCT2_GLOBAL(0x009ADAE0, sint32) != -1) { + palette = RCT2_GLOBAL(RCT2_GLOBAL(0x009ADAE0, int) + 2, int); + } + rct_g1_element g1_element = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[palette]; + int xoffset = g1_element.x_offset; + xoffset = xoffset * 4; + for (int i = 0; i < g1_element.width; i++) { + RCT2_ADDRESS(0x01424680 + xoffset, uint8)[(i * 4) + 0] = g1_element.offset[(i * 3) + 0]; + RCT2_ADDRESS(0x01424680 + xoffset, uint8)[(i * 4) + 1] = g1_element.offset[(i * 3) + 1]; + RCT2_ADDRESS(0x01424680 + xoffset, uint8)[(i * 4) + 2] = g1_element.offset[(i * 3) + 2]; + } } - if (right <= w->x || bottom <= w->y) { - continue; + // animate the water/lava/chain movement palette + int q = 0; + int weather_colour = RCT2_ADDRESS(0x98195C, uint32)[RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WEATHER_GLOOM, uint8)]; + if (weather_colour != -1) { + q = 1; + if (weather_colour != 0x2000031) { + q = 2; + } + } + uint32 j = RCT2_GLOBAL(0x009DE584, uint32); + j = (((uint16)((~j / 2) * 128) * 15) >> 16); + int p = 1533; + if (RCT2_GLOBAL(0x009ADAE0, int) != -1) { + p = RCT2_GLOBAL(RCT2_GLOBAL(0x009ADAE0, int) + 0x6, int); + } + rct_g1_element g1_element = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[q + p]; + uint8* vs = &g1_element.offset[j * 3]; + uint8* vd = RCT2_ADDRESS(0x01424A18, uint8); + int n = 5; + for (int i = 0; i < n; i++) { + vd[0] = vs[0]; + vd[1] = vs[1]; + vd[2] = vs[2]; + vs += 9; + if (vs >= &g1_element.offset[9 * n]) { + vs -= 9 * n; + } + vd += 4; } - if (RCT_WINDOW_RIGHT(w) <= left || RCT_WINDOW_BOTTOM(w) <= top) { - continue; + p = 1536; + if (RCT2_GLOBAL(0x009ADAE0, int) != -1) { + p = RCT2_GLOBAL(RCT2_GLOBAL(0x009ADAE0, int) + 0xA, int); + } + g1_element = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[q + p]; + vs = &g1_element.offset[j * 3]; + n = 5; + for (int i = 0; i < n; i++) { + vd[0] = vs[0]; + vd[1] = vs[1]; + vd[2] = vs[2]; + vs += 9; + if (vs >= &g1_element.offset[9 * n]) { + vs -= 9 * n; + } + vd += 4; } - if (left >= w->x) { - break; + j = ((uint16)(RCT2_GLOBAL(0x009DE584, uint32) * -960) * 3) >> 16; + p = 1539; + g1_element = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[q + p]; + vs = &g1_element.offset[j * 3]; + vd += 12; + n = 3; + for (int i = 0; i < n; i++) { + vd[0] = vs[0]; + vd[1] = vs[1]; + vd[2] = vs[2]; + vs += 3; + if (vs >= &g1_element.offset[3 * n]) { + vs -= 3 * n; + } + vd += 4; } - draw_rain_window(original_w, left, w->x, top, bottom, draw_rain_func); - - left = w->x; - draw_rain_window(original_w, left, right, top, bottom, draw_rain_func); - return; + RCT2_GLOBAL(0x014241BC, uint32) = 2; + osinterface_update_palette(RCT2_ADDRESS(0x01424680, uint8), 230, 16); + RCT2_GLOBAL(0x014241BC, uint32) = 0; + if (RCT2_GLOBAL(RCT2_ADDRESS_LIGHTNING_ACTIVE, uint8) == 2) { + RCT2_GLOBAL(0x014241BC, uint32) = 2; + osinterface_update_palette(RCT2_ADDRESS(0x01424680, uint8), 10, 236); + RCT2_GLOBAL(0x014241BC, uint32) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_LIGHTNING_ACTIVE, uint8) = 0; + } } - - sint16 w_right = RCT_WINDOW_RIGHT(w); - if (right > w_right) { - draw_rain_window(original_w, left, w_right, top, bottom, draw_rain_func); - - left = w_right; - draw_rain_window(original_w, left, right, top, bottom, draw_rain_func); - return; - } - - if (top < w->y) { - draw_rain_window(original_w, left, right, top, w->y, draw_rain_func); - - top = w->y; - draw_rain_window(original_w, left, right, top, bottom, draw_rain_func); - return; - } - - sint16 w_bottom = RCT_WINDOW_BOTTOM(w); - if (bottom > w_bottom) { - draw_rain_window(original_w, left, right, top, w_bottom, draw_rain_func); - - top = w_bottom; - draw_rain_window(original_w, left, right, top, bottom, draw_rain_func); - return; + if (RCT2_GLOBAL(0x009E2C4C, uint32) == 2 || RCT2_GLOBAL(0x009E2C4C, uint32) == 1) { + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_CAP_BPP, uint32) != 8) { + RCT2_GLOBAL(0x009E2C78, int) = 1; + } } } -/** -* -* rct2: 0x00684266 -*/ -void draw_rain_animation(uint32 draw_rain_func) -{ - rct_drawpixelinfo *screenDPI = RCT2_ADDRESS(RCT2_ADDRESS_SCREEN_DPI, rct_drawpixelinfo); - short left = screenDPI->x; - short right = left + screenDPI->width; - short top = screenDPI->y; - short bottom = top + screenDPI->height; - rct_window* newWindow = (RCT2_GLOBAL(RCT2_ADDRESS_NEW_WINDOW_PTR, rct_window*)); - - for (rct_window* w = g_window_list; w < newWindow; w++) { - draw_rain_window(w, left, right, top, bottom, draw_rain_func); - } -} - -/** - * - * rct2: 0x00684218 - */ -void update_rain_animation() -{ - if (RCT2_GLOBAL(0x009ABDF2, uint8) == 0) - return; - - // Draw picked-up peep - if (RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_SPRITE, uint32) != 0xFFFFFFFF) { - gfx_draw_sprite( - (rct_drawpixelinfo*)RCT2_ADDRESS_SCREEN_DPI, - RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_SPRITE, uint32), - RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_X, sint16), - RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_Y, sint16), 0 - ); - } - - // Get rain draw function and draw rain - uint32 draw_rain_func = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_RAIN_LEVEL, uint8); - if (draw_rain_func > 0 && !(RCT2_GLOBAL(0x009DEA6F, uint8) & 1)) - draw_rain_animation(draw_rain_func); -} void game_update() { @@ -349,7 +254,7 @@ void game_update() RCT2_GLOBAL(0x0141F568, uint8) = RCT2_GLOBAL(0x0013CA740, uint8); game_handle_input(); - update_water_animation(); + update_palette_effects(); update_rain_animation(); if (RCT2_GLOBAL(0x009AAC73, uint8) != 255) { @@ -379,11 +284,11 @@ void game_logic_update() RCT2_CALLPROC_EBPSAFE(0x00672AA4); // update text effects RCT2_CALLPROC_EBPSAFE(0x006ABE4C); // update rides park_update(); - RCT2_CALLPROC_EBPSAFE(0x00684C7A); - RCT2_CALLPROC_EBPSAFE(0x006B5A2A); - RCT2_CALLPROC_EBPSAFE(0x006B6456); // update ride measurements + research_update(); + RCT2_CALLPROC_EBPSAFE(0x006B5A2A); // update ride ratings + ride_measurements_update(); RCT2_CALLPROC_EBPSAFE(0x0068AFAD); - RCT2_CALLPROC_EBPSAFE(0x006BBC6B); // vehicle and scream sounds + vehicle_sounds_update();//RCT2_CALLPROC_EBPSAFE(0x006BBC6B); // vehicle and scream sounds peep_update_crowd_noise(); climate_update_sound(); news_item_update_current(); @@ -724,13 +629,18 @@ int game_load_save(const char *path) if (s6Header->num_packed_objects > 0) { j = 0; for (i = 0; i < s6Header->num_packed_objects; i++) - j += object_load_packed(); + j += object_load_packed(file); if (j > 0) object_list_load(); } } - object_read_and_load_entries(file); + if (!object_read_and_load_entries(file)){ + fclose(file); + RCT2_GLOBAL(0x009AC31B, uint8) = 255; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, uint16) = STR_FILE_CONTAINS_INVALID_DATA; + return 0; + }; // Read flags (16 bytes) sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_CURRENT_MONTH_YEAR); @@ -924,7 +834,7 @@ static uint32 game_do_command_table[58] = { 0x006A67C0, 0x00663CCD, // 20 0x006B53E9, - 0x00698D6C, + 0x00698D6C, // text input 0x0068C542, 0x0068C6D1, 0x0068BC01, diff --git a/src/game.h b/src/game.h index 72e3f63ccf..86c74c3581 100644 --- a/src/game.h +++ b/src/game.h @@ -32,7 +32,7 @@ enum GAME_COMMAND { GAME_COMMAND_7, GAME_COMMAND_SET_RIDE_OPEN, // 8 GAME_COMMAND_9, - GAME_COMMAND_10, + GAME_COMMAND_SET_RIDE_NAME, GAME_COMMAND_11, GAME_COMMAND_12, GAME_COMMAND_13, @@ -90,8 +90,7 @@ void game_create_windows(); void game_update(); void game_logic_update(); void sub_0x0069E9A7(); -void update_rain_animation(); -void update_water_animation(); +void update_palette_effects(); int game_do_command(int eax, int ebx, int ecx, int edx, int esi, int edi, int ebp); int game_do_command_p(int command, int *eax, int *ebx, int *ecx, int *edx, int *edi, int *esi, int *ebp); diff --git a/src/gfx.c b/src/gfx.c deleted file mode 100644 index ffdb445fdb..0000000000 --- a/src/gfx.c +++ /dev/null @@ -1,2391 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014 Ted John, Peter Hill, Duncan Frost - * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. - * - * This file is part of OpenRCT2. - * - * OpenRCT2 is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include "addresses.h" -#include "gfx.h" -#include "rct2.h" -#include "string_ids.h" -#include "sprites.h" -#include "window.h" -#include "osinterface.h" - -typedef struct { - uint32 num_entries; - uint32 total_size; -} rct_g1_header; - -void *_g1Buffer = NULL; - -// HACK These were originally passed back through registers -int gLastDrawStringX; -int gLastDrawStringY; - -uint8 _screenDirtyBlocks[5120]; - -//Originally 0x9ABE0C, 12 elements from 0xF3 are the peep top colour, 12 elements from 0xCA are peep trouser colour -uint8 peep_palette[0x100] = { - 0x00, 0xF3, 0xF4, 0xF5, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, - 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, - 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, - 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, - 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, - 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, - 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF -}; - -//Originally 0x9ABE04 -uint8 text_palette[0x8] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -// Previously 0x97FCBC use it to get the correct palette from g1_elements -uint16 palette_to_g1_offset[] = { - 0x1333, 0x1334, 0x1335, 0x1336, - 0x1337, 0x1338, 0x1339, 0x133A, - 0x133B, 0x133C, 0x133D, 0x133E, - 0x133F, 0x1340, 0x1341, 0x1342, - 0x1343, 0x1344, 0x1345, 0x1346, - 0x1347, 0x1348, 0x1349, 0x134A, - 0x134B, 0x134C, 0x134D, 0x134E, - 0x134F, 0x1350, 0x1351, 0x1352, - 0x1353, 0x0C1C, 0x0C1D, 0x0C1E, - 0x0C1F, 0x0C20, 0x0C22, 0x0C23, - 0x0C24, 0x0C25, 0x0C26, 0x0C21, - 0x1354, 0x1355, 0x1356, 0x1357, - 0x1358, 0x1359, 0x135A, 0x135B, - 0x135C, 0x135D, 0x135E, 0x135F, - 0x1360, 0x1361, 0x1362, 0x1363, - 0x1364, 0x1365, 0x1366, 0x1367, - 0x1368, 0x1369, 0x136A, 0x136B, - 0x136C, 0x136D, 0x136E, 0x136F, - 0x1370, 0x1371, 0x1372, 0x1373, - 0x1374, 0x1375, 0x1376, 0x1377, - 0x1378, 0x1379, 0x137A, 0x137B, - 0x137C, 0x137D, 0x137E, 0x137F, - 0x1380, 0x1381, 0x1382, 0x1383, - 0x1384, 0x1385, 0x1386, 0x1387, - 0x1388, 0x1389, 0x138A, 0x138B, - 0x138C, 0x138D, 0x138E, 0x138F, - 0x1390, 0x1391, 0x1392, 0x1393, - 0x1394, 0x1395, 0x1396, 0x1397, - 0x1398, 0x1399, 0x139A, 0x139B, - 0x139C, 0x139D, 0x139E, 0x139F, - 0x13A0, 0x13A1, 0x13A2, 0x13A3, - 0x13A4, 0x13A5, 0x13A6, 0x13A7, - 0x13A8, 0x13A9, 0x13AA, 0x13AB, - 0x13AC, 0x13AD, 0x13AE, 0x13AF, - 0x13B0, 0x13B1, 0x13B2, 0x13B3, - 0x13B4, 0x13B5, 0x13B6, 0x13B7, -}; - -static void gfx_draw_dirty_blocks(int x, int y, int columns, int rows); - -/** - * - * rct2: 0x00678998 - */ -int gfx_load_g1() -{ - FILE *file; - rct_g1_header header; - unsigned int i; - - rct_g1_element *g1Elements = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element); - - file = fopen(get_file_path(PATH_ID_G1), "rb"); - if (file != NULL) { - if (fread(&header, 8, 1, file) == 1) { - // number of elements is stored in g1.dat, but because the entry headers are static, this can't be variable until - // made into a dynamic array - header.num_entries = 29294; - - // Read element headers - fread(g1Elements, header.num_entries * sizeof(rct_g1_element), 1, file); - - // Read element data - _g1Buffer = rct2_malloc(header.total_size); - fread(_g1Buffer, header.total_size, 1, file); - - fclose(file); - - // Fix entry data offsets - for (i = 0; i < header.num_entries; i++) - g1Elements[i].offset += (int)_g1Buffer; - - // Successful - return 1; - } - fclose(file); - } - - // Unsuccessful - RCT2_ERROR("Unable to load g1.dat"); - return 0; -} - -/* -* 0x6C19AC -*/ -void gfx_load_character_widths(){ - - uint8* char_width_pointer = RCT2_ADDRESS(RCT2_ADDRESS_FONT_CHAR_WIDTH, uint8); - for (int char_set_offset = 0; char_set_offset < 4*0xE0; char_set_offset+=0xE0){ - for (uint8 c = 0; c < 0xE0; c++, char_width_pointer++){ - rct_g1_element g1 = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[c + SPR_CHAR_START + char_set_offset]; - int width; - - if (char_set_offset == 0xE0*3) width = g1.width + 1; - else width = g1.width - 1; - - if (c >= (FORMAT_ARGUMENT_CODE_START - 0x20) && c < (FORMAT_COLOUR_CODE_END - 0x20)){ - width = 0; - } - *char_width_pointer = (uint8)width; - } - - } - - uint8 drawing_surface[0x40]; - rct_drawpixelinfo dpi = { - .bits = (char*)&drawing_surface, - .width = 8, - .height = 8, - .x = 0, - .y = 0, - .pitch = 0, - .zoom_level = 0}; - - - for (int i = 0; i < 0xE0; ++i){ - memset(drawing_surface, 0, sizeof(drawing_surface)); - gfx_draw_sprite(&dpi, i + 0x10D5, -1, 0, 0); - - for (int x = 0; x < 8; ++x){ - uint8 val = 0; - for (int y = 0; y < 8; ++y){ - val >>= 1; - if (dpi.bits[x + y * 8]==1){ - val |= 0x80; - } - } - RCT2_ADDRESS(0xF4393C, uint8)[i * 8 + x] = val; - } - - } - - for (int i = 0; i < 0x20; ++i){ - rct_g1_element* g1 = &(RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[0x606 + i]); - uint8* unknown_pointer = RCT2_ADDRESS(0x9C3852, uint8) + 0xa12 * i; - g1->offset = unknown_pointer; - g1->width = 0x40; - g1->height = 0x28; - *((uint16*)unknown_pointer) = 0xFFFF; - *((uint32*)(unknown_pointer + 0x0E)) = 0; - } -} - -/** - * Clears the screen with the specified colour. - * rct2: 0x00678A9F - */ -void gfx_clear(rct_drawpixelinfo *dpi, int colour) -{ - int y, w, h; - char* ptr; - - w = dpi->width >> dpi->zoom_level; - h = dpi->height >> dpi->zoom_level; - - ptr = dpi->bits; - for (y = 0; y < h; y++) { - memset(ptr, colour, w); - ptr += w + dpi->pitch; - } -} - -void gfx_draw_pixel(rct_drawpixelinfo *dpi, int x, int y, int colour) -{ - gfx_fill_rect(dpi, x, y, x, y, colour); -} - -/* -* Draws a horizontal line of specified colour to a buffer. -* rct2: 0x68474C -*/ -void gfx_draw_line_on_buffer(rct_drawpixelinfo *dpi, char colour, int y, int x, int no_pixels) -{ - y -= dpi->y; - - //Check to make sure point is in the y range - if (y < 0)return; - if (y >= dpi->height)return; - //Check to make sure we are drawing at least a pixel - if (!no_pixels) no_pixels++; - - x -= dpi->x; - - //If x coord outside range leave - if (x < 0){ - //Unless the number of pixels is enough to be in range - no_pixels += x; - if (no_pixels <= 0)return; - //Resets starting point to 0 as we don't draw outside the range - x = 0; - } - - //Ensure that the end point of the line is within range - if (x + no_pixels - dpi->width > 0){ - //If the end point has any pixels outside range - //cut them off. If there are now no pixels return. - no_pixels -= x + no_pixels - dpi->width; - if (no_pixels <= 0)return; - } - - char* bits_pointer; - //Get the buffer we are drawing to and move to the first coordinate. - bits_pointer = dpi->bits + y*(dpi->pitch + dpi->width) + x; - - //Draw the line to the specified colour - for (; no_pixels > 0; --no_pixels, ++bits_pointer){ - *((uint8*)bits_pointer) = colour; - } -} - - -/** - * Draws a line on dpi if within dpi boundaries - * rct2: 0x00684466 - * dpi (edi) - * x1 (ax) - * y1 (bx) - * x2 (cx) - * y2 (dx) - * colour (ebp) - */ -void gfx_draw_line(rct_drawpixelinfo *dpi, int x1, int y1, int x2, int y2, int colour) -{ - // Check to make sure the line is within the drawing area - if ((x1 < dpi->x) && (x2 < dpi->x)){ - return; - } - - if ((y1 < dpi->y) && (y2 < dpi->y)){ - return; - } - - if ((x1 >(dpi->x + dpi->width)) && (x2 >(dpi->x + dpi->width))){ - return; - } - - if ((y1 > (dpi->y + dpi->height)) && (y2 > (dpi->y + dpi->height))){ - return; - } - - //Bresenhams algorithm - - //If vertical plot points upwards - int steep = abs(y2 - y1) > abs(x2 - x1); - if (steep){ - int temp_y2 = y2; - int temp_x2 = x2; - y2 = x1; - x2 = y1; - y1 = temp_x2; - x1 = temp_y2; - } - - //If line is right to left swap direction - if (x1 > x2){ - int temp_y2 = y2; - int temp_x2 = x2; - y2 = y1; - x2 = x1; - y1 = temp_y2; - x1 = temp_x2; - } - - int delta_x = x2 - x1; - int delta_y = abs(y2 - y1); - int error = delta_x / 2; - int y_step; - int y = y1; - - //Direction of step - if (y1 < y2)y_step = 1; - else y_step = -1; - - for (int x = x1, x_start = x1, no_pixels = 1; x < x2; ++x,++no_pixels){ - //Vertical lines are drawn 1 pixel at a time - if (steep)gfx_draw_line_on_buffer(dpi, colour, x, y, 1); - - error -= delta_y; - if (error < 0){ - //Non vertical lines are drawn with as many pixels in a horizontal line as possible - if (!steep)gfx_draw_line_on_buffer(dpi, colour, y, x_start, no_pixels); - - //Reset non vertical line vars - x_start = x + 1; - no_pixels = 1; - y += y_step; - error += delta_x; - } - - //Catch the case of the last line - if (x + 1 == x2 && !steep){ - gfx_draw_line_on_buffer(dpi, colour, y, x_start, no_pixels); - } - } - return; -} - -/** - * - * rct2: 0x00678AD4 - * dpi (edi) - * left (ax) - * top (cx) - * right (bx) - * bottom (dx) - * colour (ebp) - */ -void gfx_fill_rect(rct_drawpixelinfo *dpi, int left, int top, int right, int bottom, int colour) -{ - int left_, right_, top_, bottom_; - rct_drawpixelinfo* dpi_; - left_ = left; - right_ = right; - top_ = top; - bottom_ = bottom; - dpi_ = dpi; - - if ((left > right) || (top > bottom) || (dpi->x > right) || (left >= (dpi->x + dpi->width)) || - (bottom < dpi->y) || (top >= (dpi->y + dpi->height))) - return; - - colour |= RCT2_GLOBAL(0x009ABD9C, uint32); - - uint16 cross_pattern = 0; - - int start_x = left - dpi->x; - if (start_x < 0){ - start_x = 0; - cross_pattern ^= start_x; - } - - int end_x = right - dpi->x; - end_x++; - if (end_x > dpi->width) - end_x = dpi->width; - - int width = end_x - start_x; - - int start_y = top - dpi->y; - if (start_y < 0){ - start_y = 0; - cross_pattern ^= start_y; - } - int end_y = bottom - dpi->y; - end_y++; - - if (end_y > dpi->height) - end_y = dpi->height; - - int height = end_y - start_y; - if (colour&0x1000000){ - // 00678B2E 00678BE5 - //Cross hatching - uint8* dest_pointer = (start_y * (dpi->width + dpi->pitch)) + start_x + dpi->bits; - - uint32 ecx; - for (int i = 0; i < height; ++i) { - uint8* next_dest_pointer = dest_pointer + dpi->width + dpi->pitch; - ecx = cross_pattern; - // Rotate right - ecx = (ecx >> 1) | (ecx << (sizeof(ecx) * CHAR_BIT - 1)); - ecx = (ecx & 0xFFFF0000) | width; - // Fill every other pixel with the colour - for (; (ecx & 0xFFFF) > 0; ecx--) { - ecx = ecx ^ 0x80000000; - if ((int)ecx < 0) { - *dest_pointer = colour & 0xFF; - } - dest_pointer++; - } - cross_pattern ^= 1; - dest_pointer = next_dest_pointer; - - } - return; - } - if (colour & 0x2000000){ - //0x2000000 - // 00678B7E 00678C83 - // Location in screen buffer? - uint8* dest_pointer = dpi->bits + (uint32)((start_y >> (dpi->zoom_level)) * ((dpi->width >> dpi->zoom_level) + dpi->pitch) + (start_x >> dpi->zoom_level)); - - // Find colour in colour table? - uint16 eax = palette_to_g1_offset[(colour & 0xFF)]; - rct_g1_element g1_element = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[eax]; - - // Fill the rectangle with the colours from the colour table - for (int i = 0; i < height>>dpi->zoom_level; ++i) { - uint8* next_dest_pointer = dest_pointer + (dpi->width >> dpi->zoom_level) + dpi->pitch; - for (int j = 0; j < width; ++j) { - *dest_pointer = g1_element.offset[*dest_pointer]; - dest_pointer++; - } - dest_pointer = next_dest_pointer; - } - return; - } - if (colour & 0x4000000){ - //0x4000000 - // 00678B8A 00678E38 - char* dest_pointer; - dest_pointer = start_y * (dpi->width + dpi->pitch) + start_x + dpi->bits; - - //The pattern loops every 15 lines this is which - //part the pattern is on. - int pattern_y = (start_y + dpi->y) % 16; - - //The pattern loops every 15 pixels this is which - //part the pattern is on. - int start_pattern_x = (start_x + dpi_->x) % 16; - int pattern_x = start_pattern_x; - - uint16* pattern_pointer; - pattern_pointer = RCT2_ADDRESS(0x0097FEFC,uint16*)[colour >> 28]; // or possibly uint8)[esi*4] ? - - for (int no_lines = height; no_lines > 0; no_lines--) { - char* next_dest_pointer = dest_pointer + dpi->width + dpi->pitch; - uint16 pattern = pattern_pointer[pattern_y]; - - for (int no_pixels = width; no_pixels > 0; --no_pixels) { - if (pattern & (1 << pattern_x)) - *dest_pointer = colour & 0xFF; - - pattern_x = (pattern_x + 1) % 16; - dest_pointer++; - } - pattern_x = start_pattern_x; - pattern_y = (pattern_y + 1) % 16; - dest_pointer = next_dest_pointer; - } - return; - } - if (colour & 0x8000000){ - //0x8000000 - // 00678B3A 00678EC9 still to be implemented - //RCT2_CALLPROC_X(0x00678AD4, left, right, top, bottom, 0, dpi, colour); - int esi = left - RCT2_GLOBAL(0x1420070,sint16); - RCT2_GLOBAL(0xEDF824,uint32) = esi; - esi = top - RCT2_GLOBAL(0x1420072,sint16); - RCT2_GLOBAL(0xEDF828,uint32) = esi; - left -= dpi->x;//0x4 - if ( left < 0 ){ - RCT2_GLOBAL(0xEDF824,sint32) -= left; - left = 0; - } - right -= dpi->x; - right++; - if ( right > dpi->width ){ - right = dpi->width; - } - right -= left; - top -= dpi->y; - if ( top < 0 ){ - RCT2_GLOBAL(0xEDF828,sint32) -= top; - top = 0; - } - bottom -= dpi->y; - bottom++; - if (bottom > dpi->height){ - bottom = dpi->height; - } - bottom -= top; - RCT2_GLOBAL(0xEDF824,sint32) &= 0x3F; - RCT2_GLOBAL(0xEDF828,sint32) &= 0x3F; - esi = dpi->width; - esi += dpi->pitch; - esi *= top; - esi += left; - esi += (uint32)dpi->bits; - RCT2_GLOBAL(0xEDF82C,sint32) = right; - RCT2_GLOBAL(0xEDF830,sint32) = bottom; - left = dpi->width; - left+= dpi->pitch; - left-= right; - RCT2_GLOBAL(0xEDF834,sint32) = left; - colour &= 0xFF; - colour--; - right = colour; - colour <<= 8; - right |= colour; - RCT2_GLOBAL(0xEDF838,sint32) = right; - //right <<= 4; - int edi = esi; - esi = RCT2_GLOBAL(0xEDF828,sint32); - esi *= 0x40; - left = 0; - esi += (uint32)(RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS,rct_g1_element)[right]).offset;//??? - //Not finished - //Start of loop - return; - } - //0x0000000 - uint8* dest_pointer = start_y * (dpi->width + dpi->pitch) + start_x + dpi->bits; - - for (int i = 0; i < height; ++i) { - memset(dest_pointer, (colour & 0xFF), width); - dest_pointer += dpi->width + dpi->pitch; - } - // RCT2_CALLPROC_X(0x00678AD4, left, right, top, bottom, 0, dpi, colour); -} - -/** - * Draw a rectangle, with optional border or fill - * - * rct2: 0x006E6F81 - * dpi (edi) - * left (ax) - * top (cx) - * right (bx) - * bottom (dx) - * colour (ebp) - * flags (si) - */ -void gfx_fill_rect_inset(rct_drawpixelinfo* dpi, short left, short top, short right, short bottom, int colour, short flags) -{ - uint8 shadow, fill, hilight; - - // Flags - int no_border, no_fill, pressed; - - no_border = 8; - no_fill = 0x10; - pressed = 0x20; - - if (colour & 0x180) { - if (colour & 0x100) { - colour = colour & 0x7F; - } else { - colour = RCT2_ADDRESS(0x009DEDF4,uint8)[colour]; - } - - colour = colour | 0x2000000; //Transparent - - if (flags & no_border) { - gfx_fill_rect(dpi, left, top, bottom, right, colour); - } else if (flags & pressed) { - // Draw outline of box - gfx_fill_rect(dpi, left, top, left, bottom, colour + 1); - gfx_fill_rect(dpi, left, top, right, top, colour + 1); - gfx_fill_rect(dpi, right, top, right, bottom, colour + 2); - gfx_fill_rect(dpi, left, bottom, right, bottom, colour + 2); - - if (!(flags & no_fill)) { - gfx_fill_rect(dpi, left+1, top+1, right-1, bottom-1, colour); - } - } else { - // Draw outline of box - gfx_fill_rect(dpi, left, top, left, bottom, colour + 2); - gfx_fill_rect(dpi, left, top, right, top, colour + 2); - gfx_fill_rect(dpi, right, top, right, bottom, colour + 1); - gfx_fill_rect(dpi, left, bottom, right, bottom, colour + 1); - - if (!(flags & no_fill)) { - gfx_fill_rect(dpi, left+1, top+1, right-1, bottom-1, colour); - } - } - } else { - if (flags & 0x80) { - shadow = RCT2_ADDRESS(0x0141FC46, uint8)[colour * 8]; - fill = RCT2_ADDRESS(0x0141FC48, uint8)[colour * 8]; - hilight = RCT2_ADDRESS(0x0141FC4A, uint8)[colour * 8]; - } else { - shadow = RCT2_ADDRESS(0x0141FC47, uint8)[colour * 8]; - fill = RCT2_ADDRESS(0x0141FC49, uint8)[colour * 8]; - hilight = RCT2_ADDRESS(0x0141FC4B, uint8)[colour * 8]; - } - - if (flags & no_border) { - gfx_fill_rect(dpi, left, top, right, bottom, fill); - } else if (flags & pressed) { - // Draw outline of box - gfx_fill_rect(dpi, left, top, left, bottom, shadow); - gfx_fill_rect(dpi, left + 1, top, right, top, shadow); - gfx_fill_rect(dpi, right, top + 1, right, bottom - 1, hilight); - gfx_fill_rect(dpi, left + 1, bottom, right, bottom, hilight); - - if (!(flags & no_fill)) { - if (!(flags & 0x40)) { - if (flags & 0x04) { - fill = RCT2_ADDRESS(0x0141FC49, uint8)[0]; - } else { - fill = RCT2_ADDRESS(0x0141FC4A, uint8)[colour * 8]; - } - } - gfx_fill_rect(dpi, left+1, top+1, right-1, bottom-1, fill); - } - } else { - // Draw outline of box - gfx_fill_rect(dpi, left, top, left, bottom - 1, hilight); - gfx_fill_rect(dpi, left + 1, top, right - 1, top, hilight); - gfx_fill_rect(dpi, right, top, right, bottom - 1, shadow); - gfx_fill_rect(dpi, left, bottom, right, bottom, shadow); - - if (!(flags & no_fill)) { - if (flags & 0x04) { - fill = RCT2_ADDRESS(0x0141FC49, uint8)[0]; - } - gfx_fill_rect(dpi, left+1, top+1, right-1, bottom-1, fill); - } - } - } -} - -#define RCT2_Y_RELATED_GLOBAL_1 0x9E3D12 //uint16 -#define RCT2_Y_END_POINT_GLOBAL 0x9ABDAC //sint16 -#define RCT2_Y_START_POINT_GLOBAL 0xEDF808 //sint16 -#define RCT2_X_RELATED_GLOBAL_1 0x9E3D10 //uint16 -#define RCT2_X_END_POINT_GLOBAL 0x9ABDA8 //sint16 -#define RCT2_X_START_POINT_GLOBAL 0xEDF80C //sint16 -#define RCT2_DPI_LINE_LENGTH_GLOBAL 0x9ABDB0 //uint16 width+pitch - -/* -* rct2: 0x67A690 -* copies a sprite onto the buffer. There is no compression used on the sprite -* image. -*/ -void gfx_bmp_sprite_to_buffer(uint8* palette_pointer, uint8* unknown_pointer, uint8* source_pointer, uint8* dest_pointer, rct_g1_element* source_image, rct_drawpixelinfo *dest_dpi, int height, int width, int image_type){ - uint8 zoom_level = dest_dpi->zoom_level; - uint8 zoom_amount = 1 << zoom_level; - //Requires use of palette? - if (image_type & IMAGE_TYPE_USE_PALETTE){ - - //Mix with another image?? and colour adjusted - if (unknown_pointer!= NULL){ //Not tested. I can't actually work out when this code runs. - unknown_pointer += source_pointer - source_image->offset;// RCT2_GLOBAL(0x9E3CE0, uint32); - - for (; height > 0; height -= zoom_amount){ - uint8* next_source_pointer = source_pointer + (uint32)(source_image->width * zoom_amount); - uint8* next_unknown_pointer = unknown_pointer + (uint32)(source_image->width * zoom_amount); - uint8* next_dest_pointer = dest_pointer + (dest_dpi->width / zoom_amount) + dest_dpi->pitch; - - for (int no_pixels = width; no_pixels > 0; no_pixels -= zoom_amount, source_pointer += zoom_amount, unknown_pointer += zoom_amount, dest_pointer++){ - uint8 pixel = *source_pointer; - pixel = palette_pointer[pixel]; - pixel &= *unknown_pointer; - if (pixel){ - *dest_pointer = pixel; - } - } - source_pointer = next_source_pointer; - dest_pointer = next_dest_pointer; - unknown_pointer = next_unknown_pointer; - } - return; - } - - //image colour adjusted? - for (; height > 0; height -= zoom_amount){ - uint8* next_source_pointer = source_pointer + (uint32)(source_image->width * zoom_amount); - uint8* next_dest_pointer = dest_pointer + (dest_dpi->width / zoom_amount) + dest_dpi->pitch; - for (int no_pixels = width; no_pixels > 0; no_pixels -= zoom_amount, source_pointer += zoom_amount, dest_pointer++){ - uint8 pixel = *source_pointer; - pixel = palette_pointer[pixel]; - if (pixel){ - *dest_pointer = pixel; - } - } - - source_pointer = next_source_pointer; - dest_pointer = next_dest_pointer; - } - return; - } - - //Mix with background. It only uses source pointer for - //telling if it needs to be drawn not for colour. - if (image_type & IMAGE_TYPE_MIX_BACKGROUND){//Not tested - for (; height > 0; height -= zoom_amount){ - uint8* next_source_pointer = source_pointer + (uint32)(source_image->width * zoom_amount); - uint8* next_dest_pointer = dest_pointer + (dest_dpi->width / zoom_amount) + dest_dpi->pitch; - - for (int no_pixels = width; no_pixels > 0; no_pixels -= zoom_amount, source_pointer += zoom_amount, dest_pointer++){ - uint8 pixel = *source_pointer; - if (pixel){ - pixel = *dest_pointer; - pixel = palette_pointer[pixel]; - *dest_pointer = pixel; - } - } - - source_pointer = next_source_pointer; - dest_pointer = next_dest_pointer; - } - return; - } - - //Basic bitmap no fancy stuff - if (!(source_image->flags & G1_FLAG_BMP)){//Not tested - for (; height > 0; height -= zoom_amount){ - uint8* next_source_pointer = source_pointer + (uint32)(source_image->width * zoom_amount); - uint8* next_dest_pointer = dest_pointer + (dest_dpi->width / zoom_amount) + dest_dpi->pitch; - - for (int no_pixels = width; no_pixels > 0; no_pixels -= zoom_amount, dest_pointer++, source_pointer += zoom_amount){ - *dest_pointer = *source_pointer; - } - - dest_pointer = next_dest_pointer; - source_pointer = next_source_pointer; - } - return; - } - - if (RCT2_GLOBAL(0x9E3CDC, uint32) != 0){//Not tested. I can't actually work out when this code runs. - unknown_pointer += source_pointer - source_image->offset; - - for (; height > 0; height -= zoom_amount){ - uint8* next_source_pointer = source_pointer + (uint32)(source_image->width * zoom_amount); - uint8* next_unknown_pointer = unknown_pointer + (uint32)(source_image->width * zoom_amount); - uint8* next_dest_pointer = dest_pointer + (dest_dpi->width / zoom_amount) + dest_dpi->pitch; - - for (int no_pixels = width; no_pixels > 0; no_pixels -= zoom_amount, dest_pointer++, source_pointer += zoom_amount, unknown_pointer += zoom_amount){ - uint8 pixel = *source_pointer; - pixel &= *unknown_pointer; - if (pixel){ - *dest_pointer = pixel; - } - } - dest_pointer = next_dest_pointer; - source_pointer = next_source_pointer; - unknown_pointer = next_unknown_pointer; - } - } - - //Basic bitmap with no draw pixels - for (; height > 0; height -= zoom_amount){ - uint8* next_source_pointer = source_pointer + (uint32)(source_image->width * zoom_amount); - uint8* next_dest_pointer = dest_pointer + (dest_dpi->width / zoom_amount) + dest_dpi->pitch; - - for (int no_pixels = width; no_pixels > 0; no_pixels -= zoom_amount, dest_pointer++, source_pointer += zoom_amount){ - uint8 pixel = *source_pointer; - if (pixel){ - *dest_pointer = pixel; - } - } - dest_pointer = next_dest_pointer; - source_pointer = next_source_pointer; - } - return; -} - - -/* -* rct2: 0x67AA18 transfers readied images onto buffers -* This function copies the sprite data onto the screen -*/ -void gfx_rle_sprite_to_buffer(uint8* source_bits_pointer, uint8* dest_bits_pointer, uint8* palette_pointer, rct_drawpixelinfo *dpi, int image_type, int source_y_start, int height, int source_x_start, int width){ - int zoom_level = dpi->zoom_level; - int zoom_amount = 1 << zoom_level; - uint8* next_source_pointer; - uint8* next_dest_pointer = dest_bits_pointer; - - //For every line in the image - for (int y = source_y_start; y < (height + source_y_start); y += zoom_amount){ - - //The first part of the source pointer is a list of offsets to different lines - //This will move the pointer to the correct source line. - next_source_pointer = source_bits_pointer + ((uint16*)source_bits_pointer)[y]; - - uint8 last_data_line = 0; - - //For every data section in the line - while (!last_data_line){ - uint8* source_pointer = next_source_pointer; - uint8* dest_pointer = next_dest_pointer; - - int no_pixels = *source_pointer++; - //gap_size is the number of non drawn pixels you require to - //jump over on your destination - uint8 gap_size = *source_pointer++; - //The last bit in no_pixels tells you if you have reached the end of a line - last_data_line = no_pixels & 0x80; - //Clear the last data line bit so we have just the no_pixels - no_pixels &= 0x7f; - //Have our next source pointer point to the next data section - next_source_pointer = source_pointer + no_pixels; - - //Calculates the start point of the image - int x_start = gap_size - source_x_start; - - if (x_start > 0){ - //Since the start is positive - //We need to move the drawing surface to the correct position - dest_pointer += x_start / zoom_amount; - } - else{ - //If the start is negative we require to remove part of the image. - //This is done by moving the image pointer to the correct position. - source_pointer -= x_start; - //The no_pixels will be reduced in this operation - no_pixels += x_start; - //If there are no pixels there is nothing to draw this data section - if (no_pixels <= 0) continue; - //Reset the start position to zero as we have taken into account all moves - x_start = 0; - } - - int x_end = x_start + no_pixels; - //If the end position is further out than the whole image - //end position then we need to shorten the line again - if (x_end > width){ - //Shorten the line - no_pixels -= x_end - width; - //If there are no pixels there is nothing to draw. - if (no_pixels <= 0) continue; - } - - //Finally after all those checks, copy the image onto the drawing surface - //If the image type is not a basic one we require to mix the pixels - if (image_type & IMAGE_TYPE_USE_PALETTE){//In the .exe these are all unraveled loops - for (; no_pixels > 0; no_pixels -= zoom_amount, source_pointer += zoom_amount, dest_pointer++){ - uint8 al = *source_pointer; - uint8 ah = *dest_pointer; - if (image_type & IMAGE_TYPE_MIX_BACKGROUND) - al = palette_pointer[(((uint16)al << 8) | ah) - 0x100]; - else - al = palette_pointer[al]; - *dest_pointer = al; - } - } - else if (image_type & IMAGE_TYPE_MIX_BACKGROUND){//In the .exe these are all unraveled loops - //Doesnt use source pointer ??? mix with background only? - //Not Tested - - for (; no_pixels > 0; no_pixels -= zoom_amount, dest_pointer++){ - uint8 pixel = *dest_pointer; - pixel = palette_pointer[pixel]; - *dest_pointer = pixel; - } - } - else - { - for (; no_pixels > 0; no_pixels -= zoom_amount, source_pointer += zoom_amount, dest_pointer++){ - *dest_pointer = *source_pointer; - } - } - } - - //Add a line to the drawing surface pointer - next_dest_pointer += dpi->width / zoom_amount + dpi->pitch; - } -} - -/** - * - * rct2: 0x0067A28E - * image_id (ebx) - * image_id as below - * 0b_111X_XXXX_XXXX_XXXX_XXXX_XXXX_XXXX_XXXX image_type - * 0b_XXX1_11XX_XXXX_XXXX_XXXX_XXXX_XXXX_XXXX image_sub_type (unknown pointer) - * 0b_XXX1_1111_XXXX_XXXX_XXXX_XXXX_XXXX_XXXX secondary_colour - * 0b_XXXX_XXXX_1111_1XXX_XXXX_XXXX_XXXX_XXXX primary_colour - * 0b_XXXX_X111_1111_1XXX_XXXX_XXXX_XXXX_XXXX palette_ref - * 0b_XXXX_XXXX_XXXX_X111_1111_1111_1111_1111 image_id (offset to g1) - * x (cx) - * y (dx) - * dpi (esi) - * tertiary_colour (ebp) - */ -void gfx_draw_sprite(rct_drawpixelinfo *dpi, int image_id, int x, int y, uint32 tertiary_colour) -{ - //RCT2_CALLPROC_X(0x0067A28E, 0, image_id, x, y, 0, (int)dpi, tertiary_colour); - //return; - - int image_type = (image_id & 0xE0000000) >> 28; - int image_sub_type = (image_id & 0x1C000000) >> 26; - - uint8* palette_pointer = NULL; - uint8 palette[0x100]; - - RCT2_GLOBAL(0x00EDF81C, uint32) = image_id & 0xE0000000; - - uint8* unknown_pointer = (uint8*)(RCT2_ADDRESS(0x9E3CE4, uint32*)[image_sub_type]); - RCT2_GLOBAL(0x009E3CDC, uint32) = (uint32)unknown_pointer; - - if (image_type && !(image_type & IMAGE_TYPE_UNKNOWN)) { - uint8 palette_ref = (image_id >> 19) & 0xFF; - if (image_type & IMAGE_TYPE_MIX_BACKGROUND){ - unknown_pointer = NULL; - RCT2_GLOBAL(0x009E3CDC, uint32) = 0; - } - else{ - palette_ref &= 0x7F; - } - - uint16 palette_offset = palette_to_g1_offset[palette_ref]; - palette_pointer = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[palette_offset].offset; - RCT2_GLOBAL(0x9ABDA4, uint32) = (uint32)palette_pointer; - } - else if (image_type && !(image_type & IMAGE_TYPE_USE_PALETTE)){ - RCT2_GLOBAL(0x9E3CDC, uint32) = 0; - unknown_pointer = NULL; - - uint32 primary_offset = palette_to_g1_offset[(image_id >> 19) & 0x1F]; - uint32 secondary_offset = palette_to_g1_offset[(image_id >> 24) & 0x1F]; - uint32 tertiary_offset = palette_to_g1_offset[tertiary_colour]; - - rct_g1_element* primary_colour = &RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[primary_offset]; - rct_g1_element* secondary_colour = &RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[secondary_offset]; - rct_g1_element* tertiary_colour = &RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[tertiary_offset]; - - memcpy((uint8*)0x9ABFFF, &primary_colour->offset[0xF3], 12); - memcpy((uint8*)0x9ABFD6, &secondary_colour->offset[0xF3], 12); - memcpy((uint8*)0x9ABF3A, &tertiary_colour->offset[0xF3], 12); - - //image_id - RCT2_GLOBAL(0xEDF81C, uint32) |= 0x20000000; - image_id |= IMAGE_TYPE_USE_PALETTE << 28; - - RCT2_GLOBAL(0x9ABDA4, uint32) = 0x9ABF0C; - palette_pointer = (uint8*)0x9ABF0C; - } - else if (image_type){ - RCT2_GLOBAL(0x9E3CDC, uint32) = 0; - unknown_pointer = NULL; - //Copy the peep palette into a new palette. - //Not really required but its nice to make a copy - memcpy(palette, peep_palette, 0x100); - - //Top - int top_type = (image_id >> 19) & 0x1f; - uint32 top_offset = palette_to_g1_offset[top_type]; //RCT2_ADDRESS(0x97FCBC, uint32)[top_type]; - rct_g1_element top_palette = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[top_offset]; - memcpy(palette + 0xF3, top_palette.offset + 0xF3, 12); - - //Trousers - int trouser_type = (image_id >> 24) & 0x1f; - uint32 trouser_offset = palette_to_g1_offset[trouser_type]; //RCT2_ADDRESS(0x97FCBC, uint32)[trouser_type]; - rct_g1_element trouser_palette = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[trouser_offset]; - memcpy(palette + 0xCA, trouser_palette.offset + 0xF3, 12); - - //For backwards compatibility until the zooming function is done - RCT2_GLOBAL(0x9ABDA4, uint8*) = palette; - palette_pointer = palette; - } - gfx_draw_sprite_palette_set(dpi, image_id, x, y, palette_pointer, unknown_pointer); -} - -/* -* rct: 0x0067A46E -* image_id (ebx) and also (0x00EDF81C) -* palette_pointer (0x9ABDA4) -* unknown_pointer (0x9E3CDC) -* dpi (edi) -* x (cx) -* y (dx) -*/ -void gfx_draw_sprite_palette_set(rct_drawpixelinfo *dpi, int image_id, int x, int y, uint8* palette_pointer, uint8* unknown_pointer){ - int image_element = 0x7FFFF&image_id; - int image_type = (image_id & 0xE0000000) >> 28; - - rct_g1_element* g1_source = &(RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[image_element]); - - //Zooming code has been integrated into main code. - //if (dpi->zoom_level >= 1){ //These have not been tested - // //something to do with zooming - // if (dpi->zoom_level == 1){ - // RCT2_CALLPROC_X(0x0067A28E, 0, image_id, x, y, 0, (int)dpi, 0); - // return; - // } - // if (dpi->zoom_level == 2){ - // RCT2_CALLPROC_X(0x0067DADA, 0, (int)g1_source, x, y, 0, (int)dpi, 0); - // return; - // } - // RCT2_CALLPROC_X(0x0067FAAE, 0, (int)g1_source, x, y, 0, (int)dpi, 0); - // return; - //} - if ( dpi->zoom_level && (g1_source->flags & (1<<4)) ){ - rct_drawpixelinfo zoomed_dpi = { - .bits = dpi->bits, - .x = dpi->x >> 1, - .y = dpi->y >> 1, - .height = dpi->height>>1, - .width = dpi->width>>1, - .pitch = dpi->pitch, - .zoom_level = dpi->zoom_level - 1 - }; - gfx_draw_sprite_palette_set(&zoomed_dpi, (image_type << 28) | (image_element - g1_source->zoomed_offset), x >> 1, y >> 1, palette_pointer, unknown_pointer); - return; - } - - if ( dpi->zoom_level && (g1_source->flags & (1<<5)) ){ - return; - } - - //Its used super often so we will define it to a seperate variable. - int zoom_level = dpi->zoom_level; - int zoom_amount = 1 << zoom_level; - int zoom_mask = 0xFFFFFFFF << zoom_level; - - //This will be the height of the drawn image - int height = g1_source->height; - //This is the start y coordinate on the destination - sint16 dest_start_y = ((y + g1_source->y_offset)&zoom_mask) - dpi->y; - //This is the start y coordinate on the source - int source_start_y = 0; - - if (dest_start_y < 0){ - //If the destination y is negative reduce the height of the - //image as we will cut off the bottom - height += dest_start_y; - //If the image is no longer visible nothing to draw - if (height <= 0){ - return; - } - //The source image will start a further up the image - source_start_y -= dest_start_y; - //The destination start is now reset to 0 - dest_start_y = 0; - } - - int dest_end_y = dest_start_y + height; - - if (dest_end_y > dpi->height){ - //If the destination y is outside of the drawing - //image reduce the height of the image - height -= dest_end_y - dpi->height; - } - //If the image no longer has anything to draw - if (height <= 0)return; - - dest_start_y /= zoom_amount; - dest_end_y /= zoom_amount; - - //This will be the width of the drawn image - int width = g1_source->width; - //This is the source start x coordinate - int source_start_x = 0; - //This is the destination start x coordinate - sint16 dest_start_x = ((x + g1_source->x_offset) & zoom_mask) - dpi->x; - - if (dest_start_x < 0){ - //If the destination is negative reduce the width - //image will cut off the side - width += dest_start_x; - //If there is no image to draw - if (width <= 0){ - return; - } - //The source start will also need to cut off the side - source_start_x -= dest_start_x; - //Reset the destination to 0 - dest_start_x = 0; - } - - int dest_end_x = dest_start_x + width; - - if (dest_end_x > dpi->width){ - //If the destination x is outside of the drawing area - //reduce the image width. - width -= dest_end_x - dpi->width; - //If there is no image to draw. - if (width <= 0)return; - } - - dest_start_x /= zoom_amount; - dest_end_x /= zoom_amount; - - uint8* dest_pointer = (uint8*)dpi->bits; - //Move the pointer to the start point of the destination - dest_pointer += ((dpi->width / zoom_amount) + dpi->pitch)*dest_start_y + dest_start_x; - - if (g1_source->flags & G1_FLAG_RLE_COMPRESSION){ - //We have to use a different method to move the source pointer for - //rle encoded sprites so that will be handled within this function - gfx_rle_sprite_to_buffer(g1_source->offset, dest_pointer, palette_pointer, dpi, image_type, source_start_y, height, source_start_x, width); - return; - } - uint8* source_pointer = g1_source->offset; - //Move the pointer to the start point of the source - source_pointer += g1_source->width*source_start_y + source_start_x; - - if (!(g1_source->flags & 0x02)){ - gfx_bmp_sprite_to_buffer(palette_pointer, unknown_pointer, source_pointer, dest_pointer, g1_source, dpi, height, width, image_type); - return; - } - //0x67A60A Not tested - int total_no_pixels = g1_source->width*g1_source->height; - source_pointer = g1_source->offset; - uint8* new_source_pointer_start = malloc(total_no_pixels); - uint8* new_source_pointer = new_source_pointer_start;// 0x9E3D28; - int ebx, ecx; - while (total_no_pixels>0){ - sint8 no_pixels = *source_pointer; - if (no_pixels >= 0){ - source_pointer++; - total_no_pixels -= no_pixels; - memcpy((char*)new_source_pointer, (char*)source_pointer, no_pixels); - new_source_pointer += no_pixels; - source_pointer += no_pixels; - continue; - } - ecx = no_pixels; - no_pixels &= 0x7; - ecx >>= 3;//SAR - int eax = ((int)no_pixels)<<8; - ecx = -ecx;//Odd - eax = eax & 0xFF00 + *(source_pointer+1); - total_no_pixels -= ecx; - source_pointer += 2; - ebx = (uint32)new_source_pointer - eax; - eax = (uint32)source_pointer; - source_pointer = (uint8*)ebx; - ebx = eax; - eax = 0; - memcpy((char*)new_source_pointer, (char*)source_pointer, ecx); - new_source_pointer += ecx; - source_pointer += ecx; - source_pointer = (uint8*)ebx; - } - source_pointer = new_source_pointer_start + g1_source->width*source_start_y + source_start_x; - gfx_bmp_sprite_to_buffer(palette_pointer, unknown_pointer, source_pointer, dest_pointer, g1_source, dpi, height, width, image_type); - free(new_source_pointer_start); - return; -} - -/** - * - * rct2: 0x00683854 - * a1 (ebx) - * product (cl) - */ -void gfx_transpose_palette(int pal, unsigned char product) -{ - rct_g1_element g1 = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[pal]; - int width = g1.width; - int x = g1.x_offset; - uint8* dest_pointer = (uint8*)&(RCT2_ADDRESS(0x014124680,uint8)[x]); - uint8* source_pointer = g1.offset; - - for (; width > 0; width--) { - dest_pointer[0] = (source_pointer[0] * product) >> 8; - dest_pointer[1] = (source_pointer[1] * product) >> 8; - dest_pointer[2] = (source_pointer[2] * product) >> 8; - source_pointer += 3; - dest_pointer += 4; - } - osinterface_update_palette((char*)0x01424680, 10, 236);//Odd would have expected dest_pointer -} -/** - * Draws i formatted text string centred at i specified position. - * rct2: 0x006C1D6C - * dpi (edi) - * format (bx) - * x (cx) - * y (dx) - * colour (al) - * args (esi) - */ -void gfx_draw_string_centred(rct_drawpixelinfo *dpi, int format, int x, int y, int colour, void *args) -{ - char* buffer; - short text_width; - - buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char); - format_string(buffer, format, args); - - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 0xE0; - - // Measure text width - text_width = gfx_get_string_width(buffer); - - // Draw the text centred - if (text_width <= 0xFFFF) { - x -= text_width / 2; - gfx_draw_string(dpi, buffer, colour, x, y); - } -} - -/** - * - * rct2: 0x006ED7E5 - */ -void gfx_invalidate_screen() -{ - int width = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16); - int height = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16); - gfx_set_dirty_blocks(0, 0, width, height); -} - -/** - * - * rct2: 0x006E732D - * left (ax) - * top (bx) - * right (dx) - * bottom (bp) - */ -void gfx_set_dirty_blocks(int left, int top, int right, int bottom) -{ - int x, y; - uint8 *screenDirtyBlocks = RCT2_ADDRESS(0x00EDE408, uint8); - - left = max(left, 0); - top = max(top, 0); - right = min(right, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16)); - bottom = min(bottom, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16)); - - if (left >= right) - return; - if (top >= bottom) - return; - - right--; - bottom--; - - left >>= RCT2_GLOBAL(0x009ABDF0, sint8); - right >>= RCT2_GLOBAL(0x009ABDF0, sint8); - top >>= RCT2_GLOBAL(0x009ABDF1, sint8); - bottom >>= RCT2_GLOBAL(0x009ABDF1, sint8); - - for (y = top; y <= bottom; y++) - for (x = left; x <= right; x++) - screenDirtyBlocks[y * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_COLUMNS, sint32) + x] = 0xFF; -} - -/** - * - * rct2: 0x006E73BE - */ -void gfx_draw_all_dirty_blocks() -{ - int x, y, xx, yy, columns, rows; - uint8 *screenDirtyBlocks = RCT2_ADDRESS(0x00EDE408, uint8); - - for (x = 0; x < RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_COLUMNS, sint32); x++) { - for (y = 0; y < RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_ROWS, sint32); y++) { - if (screenDirtyBlocks[y * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_COLUMNS, sint32) + x] == 0) - continue; - - // Determine columns - for (xx = x; xx < RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_COLUMNS, sint32); xx++) - if (screenDirtyBlocks[y * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_COLUMNS, sint32) + xx] == 0) - break; - columns = xx - x; - - // Check rows - for (yy = y; yy < RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_ROWS, sint32); yy++) - for (xx = x; xx < x + columns; xx++) - if (screenDirtyBlocks[yy * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_COLUMNS, sint32) + xx] == 0) - goto endRowCheck; - - endRowCheck: - rows = yy - y; - gfx_draw_dirty_blocks(x, y, columns, rows); - } - } -} - -static void gfx_draw_dirty_blocks(int x, int y, int columns, int rows) -{ - int left, top, right, bottom; - uint8 *screenDirtyBlocks = RCT2_ADDRESS(0x00EDE408, uint8); - - // Unset dirty blocks - for (top = y; top < y + rows; top++) - for (left = x; left < x + columns; left++) - screenDirtyBlocks[top * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_COLUMNS, sint32) + left] = 0; - - // Determine region in pixels - left = max(0, x * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_WIDTH, sint16)); - top = max(0, y * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_HEIGHT, sint16)); - right = min(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16), left + (columns * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_WIDTH, sint16))); - bottom = min(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16), top + (rows * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_HEIGHT, sint16))); - if (right <= left || bottom <= top) - return; - - // Draw region - gfx_redraw_screen_rect(left, top, right, bottom); -} - -/** - * - * rct2: 0x006E7499 - * left (ax) - * top (bx) - * right (dx) - * bottom (bp) - */ -void gfx_redraw_screen_rect(short left, short top, short right, short bottom) -{ - rct_window* w; - rct_drawpixelinfo *screenDPI = RCT2_ADDRESS(RCT2_ADDRESS_SCREEN_DPI, rct_drawpixelinfo); - rct_drawpixelinfo *windowDPI = RCT2_ADDRESS(RCT2_ADDRESS_WINDOW_DPI, rct_drawpixelinfo); - - // Unsure what this does - RCT2_CALLPROC_X(0x00683326, left, top, right - 1, bottom - 1, 0, 0, 0); - - windowDPI->bits = screenDPI->bits + left + ((screenDPI->width + screenDPI->pitch) * top); - windowDPI->x = left; - windowDPI->y = top; - windowDPI->width = right - left; - windowDPI->height = bottom - top; - windowDPI->pitch = screenDPI->width + screenDPI->pitch + left - right; - - for (w = g_window_list; w < RCT2_GLOBAL(RCT2_ADDRESS_NEW_WINDOW_PTR, rct_window*); w++) { - if (w->flags & WF_TRANSPARENT) - continue; - if (right <= w->x || bottom <= w->y) - continue; - if (left >= w->x + w->width || top >= w->y + w->height) - continue; - window_draw(w, left, top, right, bottom); - } -} - -/** - * Return the width of the string in buffer - * - * rct2: 0x006C2321 - * buffer (esi) - */ -int gfx_get_string_width(char* buffer) -{ - // Current font sprites - uint16* current_font_sprite_base; - // Width of string - int width; - rct_g1_element g1_element; - - current_font_sprite_base = RCT2_ADDRESS(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16); - width = 0; - - for (uint8* curr_char = (uint8*)buffer; *curr_char != (uint8)0; curr_char++) { - - if (*curr_char >= 0x20) { - width += RCT2_ADDRESS(RCT2_ADDRESS_FONT_CHAR_WIDTH, uint8)[*current_font_sprite_base + (*curr_char - 0x20)]; - continue; - } - switch(*curr_char) { - case FORMAT_MOVE_X: - curr_char++; - width = *curr_char; - break; - case FORMAT_ADJUST_PALETTE: - case 3: - case 4: - curr_char++; - break; - case FORMAT_NEWLINE: - case FORMAT_NEWLINE_SMALLER: - continue; - case FORMAT_TINYFONT: - *current_font_sprite_base = 0x1C0; - break; - case FORMAT_BIGFONT: - *current_font_sprite_base = 0x2A0; - break; - case FORMAT_MEDIUMFONT: - *current_font_sprite_base = 0x0E0; - break; - case FORMAT_SMALLFONT: - *current_font_sprite_base = 0; - break; - case FORMAT_OUTLINE: - case FORMAT_OUTLINE_OFF: - case FORMAT_WINDOW_COLOUR_1: - case FORMAT_WINDOW_COLOUR_2: - case FORMAT_WINDOW_COLOUR_3: - case 0x10: - continue; - case FORMAT_INLINE_SPRITE: - g1_element = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[*((uint32*)(curr_char+1))&0x7FFFF]; - width += g1_element.width; - curr_char += 4; - break; - default: - if (*curr_char <= 0x16) { //case 0x11? FORMAT_NEW_LINE_X_Y - curr_char += 2; - continue; - } - curr_char += 4;//never happens? - break; - } - } - return width; -} - -/** - * Clip the text in buffer to width, add ellipsis and return the new width of the clipped string - * - * rct2: 0x006C2460 - * buffer (esi) - * width (edi) - */ -int gfx_clip_string(char* buffer, int width) -{ - // Location of font sprites - uint16 current_font_sprite_base; - // Width the string has to fit into - unsigned int max_width; - // Character to change to ellipsis - unsigned char* last_char; - // Width of the string, including ellipsis - - unsigned int clipped_width; - - rct_g1_element g1_element; - - if (width < 6) { - *buffer = 0; - return 0; - } - - current_font_sprite_base = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16); - max_width = width - (3 * RCT2_ADDRESS(0x141E9F6, uint8)[current_font_sprite_base]); - - clipped_width = 0; - last_char = buffer; - - for (unsigned char* curr_char = buffer; *curr_char != (uint8)0; curr_char++) { - if (*curr_char < 0x20) { - switch (*curr_char) { - case FORMAT_MOVE_X: - curr_char++; - clipped_width = *curr_char; - continue; - case FORMAT_ADJUST_PALETTE: - case 3: - case 4: - curr_char++; - continue; - case FORMAT_NEWLINE: - case FORMAT_NEWLINE_SMALLER: - continue; - case FORMAT_TINYFONT: - current_font_sprite_base = 0x1C0; - break; - case FORMAT_BIGFONT: - current_font_sprite_base = 0x2A0; - break; - case FORMAT_MEDIUMFONT: - current_font_sprite_base = 0x0E0; - break; - case FORMAT_SMALLFONT: - current_font_sprite_base = 0; - break; - case FORMAT_OUTLINE: - case FORMAT_OUTLINE_OFF: - case FORMAT_WINDOW_COLOUR_1: - case FORMAT_WINDOW_COLOUR_2: - case FORMAT_WINDOW_COLOUR_3: - case 0x10: - continue; - case FORMAT_INLINE_SPRITE: - g1_element = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[*((uint32*)(curr_char+1))&0x7FFFF]; - clipped_width += g1_element.width; - curr_char += 4; - continue; - default: - if (*curr_char <= 0x16) { //case 0x11? FORMAT_NEW_LINE_X_Y - curr_char += 2; - continue; - } - curr_char += 4;//never happens? - continue; - } - max_width = width - (3 * RCT2_ADDRESS(0x141E9F6, uint8)[current_font_sprite_base]); - } - - clipped_width += RCT2_ADDRESS(RCT2_ADDRESS_FONT_CHAR_WIDTH, uint8)[current_font_sprite_base + (*curr_char - 0x20)]; - - if ((int)clipped_width > width) { -// *((uint32*)last_char) = '...'; - strcpy(last_char-3, "..."); - clipped_width = width; - return clipped_width; - } - if (clipped_width <= max_width) { - last_char = curr_char+1; - } - } - return clipped_width; -} - - -/** - * Wrap the text in buffer to width, returns width of longest line. - * - * Inserts NULL where line should break (as \n is used for something else), - * so the number of lines is returned in num_lines. font_height seems to be - * a control character for line height. - * - * rct2: 0x006C21E2 - * buffer (esi) - * width (edi) - in - * num_lines (edi) - out - * font_height (ebx) - out - */ -int gfx_wrap_string(char* buffer, int width, int* num_lines, int* font_height) -{ - unsigned int line_width = 0; - unsigned int max_width = 0; - rct_g1_element g1_element; - - *num_lines = 0; - *font_height = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16); - - // Pointer to the start of the current word - unsigned char* curr_word = NULL; - // Width of line up to current word - unsigned int curr_width; - - for (unsigned char* curr_char = buffer; *curr_char != (uint8)0; curr_char++) { - - // Remember start of current word and line width up to this word - if (*curr_char == ' ') { - curr_word = curr_char; - curr_width = line_width; - } - - // 5 is RCT2 new line? - if (*curr_char != 5) { - if (*curr_char < ' ') { - switch(*curr_char) { - case FORMAT_MOVE_X: - case FORMAT_ADJUST_PALETTE: - case 3: - case 4: - curr_char++; - continue; - case FORMAT_NEWLINE: - case FORMAT_NEWLINE_SMALLER: - continue; - case FORMAT_TINYFONT: - *font_height = 0x1C0; - continue; - case FORMAT_BIGFONT: - *font_height = 0x2A0; - continue; - case FORMAT_MEDIUMFONT: - *font_height = 0xE0; - continue; - case FORMAT_SMALLFONT: - *font_height = 0; - continue; - case FORMAT_OUTLINE: - case FORMAT_OUTLINE_OFF: - case FORMAT_WINDOW_COLOUR_1: - case FORMAT_WINDOW_COLOUR_2: - case FORMAT_WINDOW_COLOUR_3: - case 0x10: - continue; - case FORMAT_INLINE_SPRITE: - g1_element = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[*((uint32*)(curr_char + 1)) & 0x7FFFF]; - line_width += g1_element.width; - curr_char += 4; - break; - default: - if (*curr_char <= 0x16) { - curr_char += 2; - continue; - } - curr_char += 4; - continue; - } - } - - line_width += RCT2_ADDRESS(RCT2_ADDRESS_FONT_CHAR_WIDTH, uint8)[*font_height + (*curr_char - 0x20)]; - - if ((int)line_width <= width) { - continue; - } - if (curr_word == 0) { - curr_char--; - unsigned char* old_char = curr_char; - unsigned char swap_char = 0; - unsigned char temp; - // Insert NULL at current character - // Aboslutely no guarantee that this won't overrun! - do { - temp = swap_char; - swap_char = *curr_char; - *curr_char = temp; - curr_char++; - } while(swap_char != 0); - - *curr_char = swap_char; - curr_char = old_char; - curr_char++; - *num_lines += 1; - - if (line_width > max_width) { - max_width = line_width; - } - line_width = 0; - curr_word = 0; - continue; - } - curr_char = curr_word; - line_width = curr_width; - } - - *num_lines += 1; - *curr_char = 0; - - if (line_width > max_width) { - max_width = line_width; - } - line_width = 0; - curr_word = 0; - } - if (max_width == 0)return line_width; - return max_width; -} - - -/** - * Draws i formatted text string left aligned at i specified position but clips - * the text with an elipsis if the text width exceeds the specified width. - * rct2: 0x006C1B83 - * dpi (edi) - * format (bx) - * args (esi) - * colour (al) - * x (cx) - * y (dx) - * width (bp) - */ -void gfx_draw_string_left_clipped(rct_drawpixelinfo* dpi, int format, void* args, int colour, int x, int y, int width) -{ - char* buffer; - - buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char); - format_string(buffer, format, args); - - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 0xE0; - - // Clip text - return value is not needed - gfx_clip_string(buffer, width); - - gfx_draw_string(dpi, buffer, colour, x, y); -} - -/** - * Draws i formatted text string centred at i specified position but clips the - * text with an elipsis if the text width exceeds the specified width. - * rct2: 0x006C1BBA - * dpi (edi) - * format (bx) - * args (esi) - * colour (al) - * x (cx) - * y (dx) - * width (bp) - */ -void gfx_draw_string_centred_clipped(rct_drawpixelinfo *dpi, int format, void *args, int colour, int x, int y, int width) -{ - char* buffer; - short text_width; - - buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char); - format_string(buffer, format, args); - - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 0xE0; - - // Clip text - text_width = gfx_clip_string(buffer, width); - - // Draw the text centred - if (text_width <= 0xFFFF) { - x -= (text_width - 1) / 2; - gfx_draw_string(dpi, buffer, colour, x, y); - } -} - -/** - * Draws i formatted text string right aligned. - * rct2: 0x006C1BFC - * dpi (edi) - * format (bx) - * args (esi) - * colour (al) - * x (cx) - * y (dx) - */ -void gfx_draw_string_right(rct_drawpixelinfo* dpi, int format, void* args, int colour, int x, int y) -{ - char* buffer; - short text_width; - - buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char); - format_string(buffer, format, args); - - // Measure text width - text_width = gfx_get_string_width(buffer); - - // Draw the text right aligned - x -= text_width; - gfx_draw_string(dpi, buffer, colour, x, y); -} - -/** - * - * rct2: 0x006C1E53 - * dpi (edi) - * args (esi) - * x (cx) - * y (dx) - * width (bp) - * colour (al) - * format (ebx) - */ -int gfx_draw_string_centred_wrapped(rct_drawpixelinfo *dpi, void *args, int x, int y, int width, int format, int colour) -{ - int font_height, line_height, line_width, line_y, num_lines; - // Location of font sprites - uint16* current_font_sprite_base; - - char* buffer = RCT2_ADDRESS(0x009C383D, char); - - current_font_sprite_base = RCT2_ADDRESS(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16); - *current_font_sprite_base = 0xE0; - - gfx_draw_string(dpi, buffer, colour, dpi->x, dpi->y); - - buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char); - - format_string(buffer, format, args); - - *current_font_sprite_base = 0xE0; - - // line_width unused here - line_width = gfx_wrap_string(buffer, width, &num_lines, &font_height); - - line_height = 0x0A; - - if (font_height > 0xE0) { - line_height = 6; - if (font_height != 0x1C0) { - line_height = 0x12; - } - } - - if (*buffer == 0x0B) { - line_height = line_height + 1; - } - - font_height = (line_height / 2) * num_lines; - line_y = y - font_height; - - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_FLAGS, uint16) = 0; - - for (int line = 0; line <= num_lines; ++line) { - int half_width = gfx_get_string_width(buffer) / 2; - gfx_draw_string(dpi, buffer, 0xFE, x - half_width, line_y); - - buffer += strlen(buffer) + 1; - line_y += line_height; - } - - return line_y - y; -} - -/** - * - * rct2: 0x006C2105 - * dpi (edi) - * args (esi) - * x (cx) - * y (dx) - * width (bp) - * format (bx) - * colour (al) - */ -int gfx_draw_string_left_wrapped(rct_drawpixelinfo *dpi, void *args, int x, int y, int width, int format, int colour) -{ - // font height might actually be something else - int font_height, line_height, line_width, line_y, num_lines; - - // Location of font sprites - uint16* current_font_sprite_base = RCT2_ADDRESS(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16); - *current_font_sprite_base = 0xE0; - - char* buffer = RCT2_ADDRESS(0x009C383D, char); - - gfx_draw_string(dpi, buffer, colour, dpi->x, dpi->y); - - buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char); - - format_string(buffer, format, args); - - *current_font_sprite_base = 0xE0; - - // Line width unused here - line_width = gfx_wrap_string(buffer, width, &num_lines, &font_height); - - line_height = 0x0A; - - if (font_height > 0xE0) { - line_height = 6; - if (font_height != 0x1C0) { - line_height = 0x12; - } - } - - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_FLAGS, uint16) = 0; - - line_y = y; - - for (int line = 0; line <= num_lines; ++line) { - gfx_draw_string(dpi, buffer, 0xFE, x, line_y); - buffer += strlen(buffer) + 1; - line_y += line_height; - } - - return line_y - y; -} - -/** - * Draws i formatted text string. - * rct2: 0x006C1B2F - * dpi (edi) - * format (bx) - * args (esi) - * colour (al) - * x (cx) - * y (dx) - */ -void gfx_draw_string_left(rct_drawpixelinfo *dpi, int format, void *args, int colour, int x, int y) -{ - char* buffer; - - buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char); - format_string(buffer, format, args); - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 0xE0; - gfx_draw_string(dpi, buffer, colour, x, y); -} - -/* Changes the palette so that the next character changes colour -*/ -void colour_char(uint8 colour, uint16* current_font_flags, uint8* palette_pointer) { - - int eax; - - rct_g1_element g1_element = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[0x1332]; - eax = ((uint32*)g1_element.offset)[colour & 0xFF]; - - if (!(*current_font_flags & 2)) { - eax = eax & 0x0FF0000FF; - } - // Adjust text palette. Store current colour? - palette_pointer[1] = eax & 0xFF; - palette_pointer[2] = (eax >> 8) & 0xFF; - palette_pointer[3] = (eax >> 16) & 0xFF; - palette_pointer[4] = (eax >> 24) & 0xFF; - RCT2_GLOBAL(0x009ABDA4, uint32) = (uint32)palette_pointer; -} - -/* Changes the palette so that the next character changes colour -* This is specific to changing to a predefined window related colour -*/ -void colour_char_window(uint8 colour, uint16* current_font_flags,uint8* palette_pointer) { - - int eax; - - eax = RCT2_ADDRESS(0x0141FD45, uint8)[colour * 8]; - if (*current_font_flags & 2) { - eax |= 0x0A0A00; - } - //Adjust text palette. Store current colour? - palette_pointer[1] = eax & 0xFF; - palette_pointer[2] = (eax >> 8) & 0xFF; - palette_pointer[3] = (eax >> 16) & 0xFF; - palette_pointer[4] = (eax >> 24) & 0xFF; - RCT2_GLOBAL(0x009ABDA4, uint32) = (uint32)palette_pointer; -} - - -/** - * - * rct2: 0x00682702 - * dpi (edi) - * buffer (esi) - * colour (al) - * x (cx) - * y (dx) - */ -void gfx_draw_string(rct_drawpixelinfo *dpi, char *buffer, int colour, int x, int y) -{ - - int eax, ebx, ebp; - rct_g1_element* g1_element; - - // Maximum length/height of string - int max_x = x; - int max_y = y; - - // - uint16* current_font_flags = RCT2_ADDRESS(RCT2_ADDRESS_CURRENT_FONT_FLAGS, uint16); - uint16* current_font_sprite_base = RCT2_ADDRESS(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16); - - uint8* palette_pointer = text_palette; - - // Flag for skipping non-printing characters - int skip_char = 0; - - if (colour != 0xFE) { - - if (x >= dpi->x + dpi->width) - return; - - if (x + 0x280 <= dpi->x) - return; - - if (y >= dpi->y + dpi->height) - return; - - if (y + 0x5A <= dpi->y) { - return; - } - - if (colour != 0xFF) { - - // switch_colour: - *current_font_flags = 0; - if (*current_font_sprite_base < 0) { - *current_font_flags |= 4; - if (*current_font_sprite_base != 0xFFFF) { - *current_font_flags |= 8; - } - *current_font_sprite_base = 0xE0; - } - if (colour & (1 << 5)) { - *current_font_flags |= 2; - } - colour &= ~(1 << 5); - - if (!(colour & 0x40)) { - ebp = colour; - if (*current_font_flags & 1) { - if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { - skip_char = 1; - } else { - skip_char = 0; - } - } else { - colour_char_window(ebp, current_font_flags, palette_pointer); - } - } else { - *current_font_flags |= 1; - colour &= 0x1F; - - if (*current_font_flags & 4) { - if (*current_font_flags & 8) { - eax = RCT2_ADDRESS(0x0141FC48, uint8)[colour * 8]; - eax = eax << 16; - eax = eax | RCT2_ADDRESS(0x0141FC46, uint8)[colour * 8]; - } else { - eax = RCT2_ADDRESS(0x0141FC49, uint8)[colour * 8]; - eax = eax << 16; - eax = eax | RCT2_ADDRESS(0x0141FC47, uint8)[colour * 8]; - } - } else { - eax = RCT2_ADDRESS(0x0141FC4A, uint8)[colour * 8]; - eax = eax << 16; - eax = eax | RCT2_ADDRESS(0x0141FC48, uint8)[colour * 8]; - } - // Adjust text palette. Store current colour? ; - palette_pointer[1] = eax & 0xFF; - palette_pointer[2] = (eax >> 8) & 0xFF; - palette_pointer[3] = (eax >> 16) & 0xFF; - palette_pointer[4] = (eax >> 24) & 0xFF; - RCT2_GLOBAL(0x009ABDA4, uint32) = (uint32)palette_pointer; - eax = 0; - } - } - } - - if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { - skip_char = 1; - } - - for (uint8 al = *buffer; al > 0; ++buffer, al = *buffer) { - - // Skip to the next printing character - if (skip_char) { - if (al < 0x20) { - // Control codes - skip_char = 0; - } else if (al >= FORMAT_COLOUR_CODE_START && al <= FORMAT_COLOUR_CODE_END) { - // Colour codes - if (*current_font_flags == 1) { - if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { - skip_char = 1; - } else { - skip_char = 0; - } - continue; - } - colour_char(al - FORMAT_COLOUR_CODE_START, current_font_flags, palette_pointer); - continue; - } else { - continue; - } - } - - // Control codes - switch (al) { - case FORMAT_MOVE_X://Start New Line at start+buffer x, same y. (Overwrite?) - max_x = x + *++buffer; - break; - case FORMAT_ADJUST_PALETTE: - al = *++buffer; - if (*current_font_flags & 1) { - if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { - skip_char = 1; - break; - } - } - - eax = palette_to_g1_offset[al]; //RCT2_ADDRESS(0x097FCBC, uint32)[al * 4]; - g1_element = &(RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[eax]); - ebx = g1_element->offset[0xF9] + (1 << 8); - if (!(*current_font_flags & 2)) { - ebx = ebx & 0xFF; - } - - palette_pointer[1] = ebx & 0xff; - palette_pointer[2] = (ebx >> 8) & 0xff; - //Adjust the text palette - memcpy(palette_pointer + 3, &(g1_element->offset[0xF7]), 2); - memcpy(palette_pointer + 5, &(g1_element->offset[0xFA]), 2); - //Set the palette pointer - RCT2_GLOBAL(0x009ABDA4, uint32) = (uint32)palette_pointer; - - - if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { - skip_char = 1; - } - break; - case FORMAT_NEWLINE://Start New Line at set y lower - max_x = x; - if (*current_font_sprite_base <= 0xE0) { - max_y += 10; - break; - } - else if (*current_font_sprite_base == 0x1C0) { - max_y += 6; - break; - } - max_y += 18; - break; - case FORMAT_NEWLINE_SMALLER://Start New Line at set y lower - max_x = x; - if (*current_font_sprite_base <= 0xE0) { - max_y += 5; - break; - } - else if (*current_font_sprite_base == 0x1C0) { - max_y += 3; - break; - } - max_y += 9; - break; - case FORMAT_TINYFONT: - *current_font_sprite_base = 0x1C0; - break; - case FORMAT_BIGFONT: - *current_font_sprite_base = 0x2A0; - break; - case FORMAT_MEDIUMFONT: - *current_font_sprite_base = 0xE0; - break; - case FORMAT_SMALLFONT: - *current_font_sprite_base = 0; - break; - case FORMAT_OUTLINE: - *current_font_flags |= 2; - break; - case FORMAT_OUTLINE_OFF: - *current_font_flags &= 0x0FFFD; - break; - case FORMAT_WINDOW_COLOUR_1: - ebp = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WINDOW_COLOUR_1, uint8); - if (*current_font_flags & 1) { - if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { - skip_char = 1; - } - else { - skip_char = 0; - } - break; - } - colour_char_window(ebp, current_font_flags, palette_pointer); - break; - case FORMAT_WINDOW_COLOUR_2: - ebp = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WINDOW_COLOUR_2, uint8); - if (*current_font_flags & 1) { - if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { - skip_char = 1; - } - else { - skip_char = 0; - } - break; - } - colour_char_window(ebp, current_font_flags, palette_pointer); - break; - case FORMAT_WINDOW_COLOUR_3: - ebp = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WINDOW_COLOUR_3, uint8); - if (*current_font_flags & 1) { - if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { - skip_char = 1; - } - else { - skip_char = 0; - } - break; - } - colour_char_window(ebp, current_font_flags, palette_pointer); - break; - case FORMAT_NEWLINE_X_Y: //Start new line at specified x,y - max_x = x + *++buffer; - max_y = y + *++buffer; - break; - case FORMAT_INLINE_SPRITE: - buffer += 4; - if (max_x >= dpi->x + dpi->width) { - skip_char = 1; - break; - } - ebx = *((uint16*)(buffer - 3)); - eax = ebx & 0x7FFFF; - g1_element = &(RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[eax]); - - gfx_draw_sprite(dpi, ebx, max_x, max_y, 0); - - max_x = max_x + g1_element->width; - break; - default: - // Colour codes - if ((al >= FORMAT_COLOUR_CODE_START) && (al <= FORMAT_COLOUR_CODE_END)){ - - if (*current_font_flags == 1) { - if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { - skip_char = 1; - } else { - skip_char = 0; - } - continue; - } - colour_char(al - FORMAT_COLOUR_CODE_START, current_font_flags, palette_pointer); - continue; - } - - // Normal Characters - if (max_x >= dpi->x + dpi->width) { - skip_char = 1; - } - if (max_x + 0x1A < dpi->x) { - ebx = al-0x20; - ebx += *current_font_sprite_base; - max_x = max_x + (RCT2_ADDRESS(RCT2_ADDRESS_FONT_CHAR_WIDTH, uint8)[ebx] & 0xFF); - continue; - } - - uint32 char_offset = al - 0x20 + *current_font_sprite_base; - RCT2_GLOBAL(0x00EDF81C, uint32) = (IMAGE_TYPE_USE_PALETTE << 28); - - gfx_draw_sprite_palette_set(dpi, (IMAGE_TYPE_USE_PALETTE << 28) | char_offset + SPR_CHAR_START, max_x, max_y, palette_pointer, NULL); - max_x += (RCT2_ADDRESS(RCT2_ADDRESS_FONT_CHAR_WIDTH, uint8)[char_offset] & 0xFF); - continue; - } - } - - gLastDrawStringX = max_x; - gLastDrawStringY = max_y; -} - -/* -* -* rct2: 0x006EE53B -* left (ax) -* width (bx) -* top (cx) -* height (dx) -* drawpixelinfo (edi) -*/ -rct_drawpixelinfo* clip_drawpixelinfo(rct_drawpixelinfo* dpi, int left, int width, int top, int height) -{ - rct_drawpixelinfo* newDrawPixelInfo = rct2_malloc(sizeof(rct_drawpixelinfo)); - - int right = left + width; - int bottom = top + height; - - newDrawPixelInfo->bits = dpi->bits; - newDrawPixelInfo->x = dpi->x; - newDrawPixelInfo->y = dpi->y; - newDrawPixelInfo->width = dpi->width; - newDrawPixelInfo->height = dpi->height; - newDrawPixelInfo->pitch = dpi->pitch; - newDrawPixelInfo->zoom_level = 0; - - if (left > newDrawPixelInfo->x) { - uint16 clippedFromLeft = left - newDrawPixelInfo->x; - newDrawPixelInfo->width -= clippedFromLeft; - newDrawPixelInfo->x = left; - newDrawPixelInfo->pitch += clippedFromLeft; - newDrawPixelInfo->bits += clippedFromLeft; - } - - int stickOutWidth = newDrawPixelInfo->x + newDrawPixelInfo->width - right; - if (stickOutWidth > 0) { - newDrawPixelInfo->width -= stickOutWidth; - newDrawPixelInfo->pitch += stickOutWidth; - } - - if (top > newDrawPixelInfo->y) { - uint16 clippedFromTop = top - newDrawPixelInfo->y; - newDrawPixelInfo->height -= clippedFromTop; - newDrawPixelInfo->y = top; - uint32 bitsPlus = (newDrawPixelInfo->pitch + newDrawPixelInfo->width) * clippedFromTop; - newDrawPixelInfo->bits += bitsPlus; - } - - int bp = newDrawPixelInfo->y + newDrawPixelInfo->height - bottom; - if (bp > 0) { - newDrawPixelInfo->height -= bp; - } - - if (newDrawPixelInfo->width > 0 && newDrawPixelInfo->height > 0) { - newDrawPixelInfo->x -= left; - newDrawPixelInfo->y -= top; - - return newDrawPixelInfo; - } - - rct2_free(newDrawPixelInfo); - return NULL; -} - -/*** -* -* rct2: 0x00684027 -* -* ebp used to be a parameter but it is always zero -* left : eax -* top : ebx -* width : ecx -* height : edx -* x_start: edi -* y_start: esi -*/ -void gfx_draw_rain(int left, int top, int width, int height, sint32 x_start, sint32 y_start){ - uint8* pattern = RCT2_GLOBAL(RCT2_ADDRESS_RAIN_PATTERN, uint8*); - uint8 pattern_x_space = *pattern++; - uint8 pattern_y_space = *pattern++; - - uint8 pattern_start_x_offset = x_start % pattern_x_space; - uint8 pattern_start_y_offset = y_start % pattern_y_space;; - - rct_drawpixelinfo* dpi = RCT2_ADDRESS(RCT2_ADDRESS_SCREEN_DPI, rct_drawpixelinfo); - uint32 pixel_offset = (dpi->pitch + dpi->width)*top + left; - uint8 pattern_y_pos = pattern_start_y_offset; - - //Stores the colours of changed pixels - uint32* pixel_store = RCT2_ADDRESS(RCT2_ADDRESS_RAIN_PIXEL_STORE, uint32); - pixel_store += RCT2_GLOBAL(RCT2_ADDRESS_NO_RAIN_PIXELS, uint32); - - for (; height != 0; height--){ - uint8 pattern_x = pattern[pattern_y_pos * 2]; - if (pattern_x != 0xFF){ - if (RCT2_GLOBAL(0x9AC00C, uint32) <= 0x1F38){ - - int final_pixel_offset = width + pixel_offset; - - int x_pixel_offset = pixel_offset; - x_pixel_offset += ((uint8)(pattern_x - pattern_start_x_offset)) % pattern_x_space; - - uint8 pattern_pixel = pattern[pattern_y_pos * 2 + 1]; - for (; x_pixel_offset < final_pixel_offset; x_pixel_offset += pattern_x_space){ - uint8 current_pixel = dpi->bits[x_pixel_offset]; - dpi->bits[x_pixel_offset] = pattern_pixel; - RCT2_GLOBAL(RCT2_ADDRESS_NO_RAIN_PIXELS, uint32)++; - - //Store colour and position - *pixel_store++ = (x_pixel_offset << 8) | current_pixel; - } - } - } - - pixel_offset += dpi->pitch + dpi->width; - - pattern_y_pos++; - pattern_y_pos %= pattern_y_space; - } -} - -void draw_string_left_underline(rct_drawpixelinfo *dpi, int format, void *args, int colour, int x, int y) -{ - char buffer[128]; - int width; - - format_string(buffer, format, args); - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 224; - width = gfx_get_string_width(buffer); - gfx_draw_string(dpi, buffer, colour, x, y); - gfx_fill_rect(dpi, x, y + 11, x + width, y + 11, text_palette[1]); - if (text_palette[2] != 0) - gfx_fill_rect(dpi, x + 1, y + 12, x + width + 1, y + 12, text_palette[2]); -} - -void draw_string_right_underline(rct_drawpixelinfo *dpi, int format, void *args, int colour, int x, int y) -{ - char buffer[128]; - int width; - - format_string(buffer, format, args); - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 224; - width = gfx_get_string_width(buffer); - x -= width; - gfx_draw_string(dpi, buffer, colour, x, y); - gfx_fill_rect(dpi, x, y + 11, x + width, y + 11, text_palette[1]); - if (text_palette[2] != 0) - gfx_fill_rect(dpi, x + 1, y + 12, x + width + 1, y + 12, text_palette[2]); -} diff --git a/src/hook.c b/src/hook.c new file mode 100644 index 0000000000..6c8dd9395a --- /dev/null +++ b/src/hook.c @@ -0,0 +1,201 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of OpenRCT2. + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#include +#include "hook.h" + +void* g_hooktableaddress = 0; +int g_hooktableoffset = 0; +int g_maxhooks = 1000; + +void hookfunc(int address, int newaddress, int stacksize, int registerargs[], int registersreturned) +{ + int i = 0; + char data[100]; + + int registerssaved = 7; + int n = registersreturned; + for (; n; registerssaved--) { + n &= n - 1; + } + int numrargs = 0; + for (int j = 0; ; j++) { + if (registerargs[j] != END) { + numrargs++; + } else { + break; + } + } + + int rargssize = numrargs * 4; + + data[i++] = 0x50; // push eax + + // move stack down for possible existing arguments + for (int j = 0; j < stacksize; j++) { + data[i++] = 0x8B; // mov eax, [esp+x] + data[i++] = 0x44; + data[i++] = 0xE4; + data[i++] = (signed char)((4 * (stacksize - j)) + 4); + + data[i++] = 0x89; // mov [esp+x], eax + data[i++] = 0x44; + data[i++] = 0xE4; + data[i++] = (signed char)((4 * (stacksize - j)) - ((registerssaved + stacksize) * 4)); + } + + if (numrargs > 0) { + // push the registers to be on the stack to access as arguments + data[i++] = 0x83; // add esp, x + data[i++] = 0xC4; + data[i++] = -((registerssaved + stacksize) * 4) + 4; + + for (signed int j = numrargs - 1; j >= 0; j--) { + switch (registerargs[j]) { + case EAX: data[i++] = 0x50; break; + case EBX: data[i++] = 0x53; break; + case ECX: data[i++] = 0x51; break; + case EDX: data[i++] = 0x52; break; + case ESI: data[i++] = 0x56; break; + case EDI: data[i++] = 0x57; break; + case EBP: data[i++] = 0x55; break; + } + } + + data[i++] = 0x83; // add esp, x + data[i++] = 0xC4; + data[i++] = rargssize + ((registerssaved + stacksize) * 4) - 4; + } + + + data[i++] = 0xE8; // call + data[i++] = 0x00; + data[i++] = 0x00; + data[i++] = 0x00; + data[i++] = 0x00; + + int sizec = i; + + data[i++] = 0x8B; // push eax, [esp] - puts eip in eax + data[i++] = 0x04; + data[i++] = 0xE4; + + data[i++] = 0x83; // add eax, x + data[i++] = 0xC0; + int sizeoffset = i; + data[i++] = 0; // set to returnlocation offset later + + data[i++] = 0x89; // mov [esp-20h], eax - put return address on stack + data[i++] = 0x44; + data[i++] = 0xE4; + data[i++] = (signed char)(-(registerssaved * 4) - rargssize - (stacksize * 4)) + 4; + + data[i++] = 0x83; // add esp, x + data[i++] = 0xC4; + data[i++] = 4; + + data[i++] = 0x58; // pop eax + + if (!(registersreturned & EAX)) { + data[i++] = 0x50; // push eax + } + if (!(registersreturned & EBX)) { + data[i++] = 0x53; // push ebx + } + if (!(registersreturned & ECX)) { + data[i++] = 0x51; // push ecx + } + if (!(registersreturned & EDX)) { + data[i++] = 0x52; // push edx + } + if (!(registersreturned & EBP)) { + data[i++] = 0x55; // push ebp + } + if (!(registersreturned & ESI)) { + data[i++] = 0x56; // push esi + } + if (!(registersreturned & EDI)) { + data[i++] = 0x57; // push edi + } + + data[i++] = 0x83; // sub esp, x + data[i++] = 0xEC; + data[i++] = 4 + (stacksize * 4) + rargssize; + + data[i++] = 0xEA; // jmp + *((int *)&data[i]) = newaddress; i += 4; + data[i++] = 0x23; + data[i++] = 0x00; + + data[sizeoffset] = i - sizec; + + // returnlocation: + + data[i++] = 0x83; // sub esp, x + data[i++] = 0xEC; + data[i++] = (signed char)(stacksize * -4) - rargssize; + + if (!(registersreturned & EDI)) { + data[i++] = 0x5F; // pop edi + } + if (!(registersreturned & ESI)) { + data[i++] = 0x5E; // pop esi + } + if (!(registersreturned & EBP)) { + data[i++] = 0x5D; // pop ebp + } + if (!(registersreturned & EDX)) { + data[i++] = 0x5A; // pop edx + } + if (!(registersreturned & ECX)) { + data[i++] = 0x59; // pop ecx + } + if (!(registersreturned & EBX)) { + data[i++] = 0x5B; // pop ebx + } + if (!(registersreturned & EAX)) { + data[i++] = 0x58; // pop eax + } + + data[i++] = 0xC3; // retn + + WriteProcessMemory(GetCurrentProcess(), (LPVOID)address, data, i, 0); +} + +void addhook(int address, int newaddress, int stacksize, int registerargs[], int registersreturned) +{ + if (!g_hooktableaddress) { + g_hooktableaddress = VirtualAllocEx(GetCurrentProcess(), NULL, g_maxhooks * 100, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + } + if (g_hooktableoffset > g_maxhooks) { + return; + } + unsigned int hookaddress = (unsigned int)g_hooktableaddress + (g_hooktableoffset * 100); + char data[9]; + int i = 0; + data[i++] = 0xEA; // jmp + *((int *)&data[i]) = hookaddress; i += 4; + data[i++] = 0x23; + data[i++] = 0x00; + data[i++] = 0xC3; // retn + WriteProcessMemory(GetCurrentProcess(), (LPVOID)address, data, i, 0); + hookfunc(hookaddress, newaddress, stacksize, registerargs, registersreturned); + g_hooktableoffset++; +} \ No newline at end of file diff --git a/src/hook.h b/src/hook.h new file mode 100644 index 0000000000..fed10792f3 --- /dev/null +++ b/src/hook.h @@ -0,0 +1,37 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of OpenRCT2. + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#ifndef _HOOK_H_ +#define _HOOK_H_ + +enum REGISTER_ARGS { + EAX = 1 << 0, + EBX = 1 << 1, + ECX = 1 << 2, + EDX = 1 << 3, + ESI = 1 << 4, + EDI = 1 << 5, + EBP = 1 << 6, + END = 0 +}; + +void addhook(int address, int newaddress, int stacksize, int registerargs[], int registersreturned); + +#endif \ No newline at end of file diff --git a/src/input.c b/src/input.c index 725b6e9eb9..0ce7dd188f 100644 --- a/src/input.c +++ b/src/input.c @@ -21,18 +21,19 @@ #include #include #include "addresses.h" -#include "audio.h" +#include "audio/audio.h" #include "config.h" #include "game.h" #include "input.h" -#include "map.h" -#include "osinterface.h" -#include "sprite.h" +#include "interface/viewport.h" +#include "interface/widget.h" +#include "interface/window.h" +#include "platform/osinterface.h" #include "tutorial.h" -#include "viewport.h" -#include "widget.h" -#include "window.h" -#include "window_tooltip.h" +#include "windows/tooltip.h" +#include "windows/dropdown.h" +#include "world/map.h" +#include "world/sprite.h" POINT _dragPosition; @@ -48,7 +49,7 @@ static void input_mouseover(int x, int y, rct_window *w, int widgetIndex); static void input_mouseover_widget_check(rct_windowclass windowClass, rct_windownumber windowNumber, int widgetIndex); static void input_mouseover_widget_flatbutton_invalidate(); void process_mouse_over(int x, int y); -void sub_6ED801(int x, int y); +void process_mouse_tool(int x, int y); void invalidate_scroll(); static rct_mouse_data* get_mouse_input(); @@ -530,10 +531,12 @@ static void input_leftmousedown(int x, int y, rct_window *w, int widgetIndex) } break; default: - if (!widget_is_enabled(w, widgetIndex)) - break; + if (!widget_is_enabled(w, widgetIndex)) + break; + if (widget_is_disabled(w, widgetIndex)) + break; - sound_play_panned(SOUND_CLICK_1, w->x + (widget->left + widget->right) / 2); + sound_play_panned(SOUND_CLICK_1, w->x + (widget->left + widget->right) / 2, 0, 0, 0); // Set new cursor down widget RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WINDOWCLASS, rct_windowclass) = windowClass; @@ -549,6 +552,145 @@ static void input_leftmousedown(int x, int y, rct_window *w, int widgetIndex) } } +/* rct2: 0x6E8DA7 */ +void input_state_widget_pressed( int x, int y, int state, int widgetIndex, rct_window* w, rct_widget* widget ){ + //RCT2_CALLPROC_X(0x006E8DA7, x, y, state, widgetIndex, (int)w, (int)widget, 0); + //return; + RCT2_GLOBAL(0x1420054, uint16) = x; + RCT2_GLOBAL(0x1420056, uint16) = y; + + rct_windowclass cursor_w_class; + rct_windownumber cursor_w_number; + cursor_w_class = RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WINDOWCLASS, rct_windowclass); + cursor_w_number = RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WINDOWNUMBER, rct_windownumber); + int cursor_widgetIndex = RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WIDGETINDEX, uint32); + + rct_window* cursor_w = window_find_by_id(cursor_w_class, cursor_w_number); + if (!cursor_w){ + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = 0; + return; + } + + + + switch (state){ + case 0: + if (!w || cursor_w_class != w->classification || cursor_w_number != w->number || widgetIndex != cursor_widgetIndex) + break; + + if (w->disabled_widgets & (1ULL << widgetIndex)) + break; + + if (RCT2_GLOBAL(0x9DE528, uint16) != 0) RCT2_GLOBAL(0x9DE528, uint16)++; + + if (w->var_020 & (1ULL << widgetIndex) && + RCT2_GLOBAL(0x9DE528, uint16) >= 0x10 && + (!(RCT2_GLOBAL(0x9DE528, uint16) & 0x3))){ + RCT2_CALLPROC_WE_MOUSE_DOWN(w->event_handlers[WE_MOUSE_DOWN], widgetIndex, w, widget); + } + + if (RCT2_GLOBAL(0x9DE518, uint32) & 1) return; + + RCT2_GLOBAL(0x9DE518, uint32) |= 1; + widget_invalidate(cursor_w_class, cursor_w_number, widgetIndex); + return; + case 3: + case 2: + if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) == 5){ + if (w) { + int dropdown_index = 0; + + if (w->classification == WC_DROPDOWN){ + dropdown_index = dropdown_index_from_point(x, y, w); + if (dropdown_index == -1)goto dropdown_cleanup; + + // _dropdown_unknown?? highlighted? + if (dropdown_index < 32 && RCT2_GLOBAL(0x009DED34, sint32) & (1 << dropdown_index))goto dropdown_cleanup; + + // gDropdownItemsFormat[dropdown_index] will not work until all windows that use dropdown decompiled + if (RCT2_ADDRESS(0x9DEBA4, uint16)[dropdown_index] == 0)goto dropdown_cleanup; + } + else{ + if (cursor_w_class != w->classification || cursor_w_number != w->number || widgetIndex != cursor_widgetIndex) + goto dropdown_cleanup; + dropdown_index = -1; + if (RCT2_GLOBAL(0x9DE518, uint32) & 2){ + if (!(RCT2_GLOBAL(0x9DE518, uint32) & 4)){ + RCT2_GLOBAL(0x9DE518, uint32) |= (1 << 2); + return; + } + } + } + + window_close_by_id(WC_DROPDOWN, 0); + cursor_w = window_find_by_id(cursor_w_class, cursor_w_number); + if (RCT2_GLOBAL(0x9DE518, uint32) & 1){ + RCT2_GLOBAL(0x9DE518, uint32) &= 0xFFFE; + widget_invalidate(cursor_w_class, cursor_w_number, cursor_widgetIndex); + } + + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = 1; + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TIMEOUT, uint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WIDGET_INDEX, uint16) = cursor_widgetIndex; + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_CLASS, rct_windowclass) = cursor_w_class; + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_NUMBER, rct_windownumber) = cursor_w_number; + RCT2_CALLPROC_X(cursor_w->event_handlers[WE_DROPDOWN], dropdown_index, 0, 0, cursor_widgetIndex, (int)cursor_w, 0, 0); + } + dropdown_cleanup: + window_close_by_id(WC_DROPDOWN, 0); + } + if (state == 3) return; + + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = 1; + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TIMEOUT, uint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WIDGET_INDEX, uint16) = cursor_widgetIndex; + + if (!w) + break; + + int mid_point_x = (widget->left + widget->right) / 2 + w->x; + sound_play_panned(5, mid_point_x, 0, 0, 0); + if (cursor_w_class != w->classification || cursor_w_number != w->number || widgetIndex != cursor_widgetIndex) + break; + + if (w->disabled_widgets & (1ULL << widgetIndex)) + break; + + widget_invalidate(cursor_w_class, cursor_w_number, widgetIndex); + window_event_helper(w, widgetIndex, WE_MOUSE_UP); + default: + return; + } + + RCT2_GLOBAL(0x9DE528, uint16) = 0; + if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) != 5){ + // Hold down widget and drag outside of area?? + if (RCT2_GLOBAL(0x9DE518, uint32) & 1){ + RCT2_GLOBAL(0x9DE518, uint32) &= 0xFFFE; + widget_invalidate(cursor_w_class, cursor_w_number, cursor_widgetIndex); + } + return; + } + + if (!w) return; + + if (w->classification == WC_DROPDOWN){ + int dropdown_index = dropdown_index_from_point(x, y, w); + + if (dropdown_index == -1) return; + + // _dropdown_unknown?? highlighted? + if (dropdown_index < 32 && RCT2_GLOBAL(0x009DED34, sint32) & (1 << dropdown_index))return; + + // gDropdownItemsFormat[dropdown_index] will not work until all windows that use dropdown decompiled + if (RCT2_ADDRESS(0x9DEBA4, uint16)[dropdown_index] == 0)return; + + // _dropdown_highlighted_index + RCT2_GLOBAL(0x009DEBA2, sint16) = dropdown_index; + window_invalidate_by_id(WC_DROPDOWN, 0); + } +} + /** * * rct2: 0x006E8655 @@ -612,7 +754,8 @@ static void game_handle_input_mouse(int x, int y, int state) break; case INPUT_STATE_WIDGET_PRESSED: - RCT2_CALLPROC_X(0x006E8DA7, x, y, state, widgetIndex, (int)w, (int)widget, 0); + input_state_widget_pressed(x, y, state, widgetIndex, w, widget); + //RCT2_CALLPROC_X(0x006E8DA7, x, y, state, widgetIndex, (int)w, (int)widget, 0); break; case INPUT_STATE_DRAGGING: // RCT2_CALLPROC_X(0x006E8C5C, x, y, state, widgetIndex, w, widget, 0); @@ -728,7 +871,8 @@ static void game_handle_input_mouse(int x, int y, int state) break; } case INPUT_STATE_DROPDOWN_ACTIVE: - RCT2_CALLPROC_X(0x006E8DA7, x, y, state, widgetIndex, (int)w, (int)widget, 0); + input_state_widget_pressed(x, y, state, widgetIndex, w, widget); + //RCT2_CALLPROC_X(0x006E8DA7, x, y, state, widgetIndex, (int)w, (int)widget, 0); break; case INPUT_STATE_VIEWPORT_LEFT: //RCT2_CALLPROC_X(0x006E87B4, x, y, state, widgetIndex, (int)w, (int)widget, 0); @@ -756,7 +900,7 @@ static void game_handle_input_mouse(int x, int y, int state) } else if (state == 2){ - RCT2_GLOBAL(0x9DE51D, uint8) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = 0; if (RCT2_GLOBAL(0x9DE52E, rct_windownumber) != w->number)break; if ((RCT2_GLOBAL(0x9DE518, uint32)&(1 << 3))){ w = window_find_by_id(RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass), RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber)); @@ -775,7 +919,7 @@ static void game_handle_input_mouse(int x, int y, int state) RCT2_CALLPROC_X(0x6ACAC2, eax, ebx, ecx, (int)spr, esi, edi, ebp); } else if (spr->unknown.sprite_identifier == SPRITE_IDENTIFIER_PEEP){ - window_peep_open(&spr->peep); + window_guest_open(&spr->peep); } else if (spr->unknown.sprite_identifier == SPRITE_IDENTIFIER_FLOATING_TEXT){ //Unknown for now @@ -789,7 +933,7 @@ static void game_handle_input_mouse(int x, int y, int state) eax = RCT2_ADDRESS(0x0099BA64, uint8)[16 * map_element->properties.track.type]; if (!(eax & 0x10)){//If not station track //Open ride window in overview mode. - RCT2_CALLPROC_X(0x6ACC28, map_element->properties.track.ride_index, ebx, ecx, (int)map_element, esi, edi, ebp); + window_ride_main_open(map_element->properties.track.ride_index); break; } } @@ -918,7 +1062,7 @@ static void input_mouseover(int x, int y, rct_window *w, int widgetIndex) { rct_windowclass windowClass = 255; rct_windownumber windowNumber = 0; - rct_widget *widget; + rct_widget *widget = NULL; if (w != NULL) { windowClass = w->classification; @@ -1546,7 +1690,7 @@ void game_handle_input() // RCT2_CALLPROC_X(0x006E8655, eax, ebx, 0, 0, 0, 0, 0); // window_process_mouse_input process_mouse_over(eax, ebx); //RCT2_CALLPROC_X(0x006ED833, eax, ebx, 0, 0, 0, 0, 0); - sub_6ED801(eax, ebx); + process_mouse_tool(eax, ebx); //RCT2_CALLPROC_EBPSAFE(0x006ED801); } } @@ -1601,15 +1745,17 @@ static void game_get_next_input(int *x, int *y, int *state) * * rct2: 0x006ED801 */ -void sub_6ED801(int x, int y){ - if (RCT2_GLOBAL(0x9DE518, uint32) & (1 << 3)){ +void process_mouse_tool(int x, int y) +{ + if (RCT2_GLOBAL(0x9DE518, uint32) & (1 << 3)) + { rct_window* w = window_find_by_id(RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, uint8), RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, uint16)); - if (w == NULL){ + + if (!w) tool_cancel(); - } - else{ + else RCT2_CALLPROC_X(w->event_handlers[WE_TOOL_UPDATE], x, y, 0, RCT2_GLOBAL(0x9DE546, uint16), (int)w, 0, 0); - } + } } diff --git a/src/input.h b/src/input.h index dd1cc5b3fb..0a40da1636 100644 --- a/src/input.h +++ b/src/input.h @@ -23,6 +23,7 @@ void game_handle_input(); void game_handle_keyboard_input(); +void handle_shortcut_command(int shortcutIndex); void store_mouse_input(int state); diff --git a/src/graph.c b/src/interface/graph.c similarity index 98% rename from src/graph.c rename to src/interface/graph.c index 9cb39f564c..96917c88af 100644 --- a/src/graph.c +++ b/src/interface/graph.c @@ -18,10 +18,10 @@ * along with this program. If not, see . *****************************************************************************/ -#include "addresses.h" -#include "date.h" +#include "../addresses.h" +#include "../localisation/date.h" +#include "../localisation/localisation.h" #include "graph.h" -#include "string_ids.h" static void graph_draw_months_uint8(rct_drawpixelinfo *dpi, uint8 *history, int count, int baseX, int baseY) { diff --git a/src/graph.h b/src/interface/graph.h similarity index 95% rename from src/graph.h rename to src/interface/graph.h index 03622b7a2c..82a0f7fa6c 100644 --- a/src/graph.h +++ b/src/interface/graph.h @@ -21,8 +21,8 @@ #ifndef _GRAPH_H_ #define _GRAPH_H_ -#include "gfx.h" -#include "rct2.h" +#include "../common.h" +#include "../drawing/drawing.h" void graph_draw_uint8(rct_drawpixelinfo *dpi, uint8 *history, int count, int baseX, int baseY); void graph_draw_money32(rct_drawpixelinfo *dpi, money32 *history, int count, int baseX, int baseY, int modifier, int offset); diff --git a/src/screenshot.c b/src/interface/screenshot.c similarity index 96% rename from src/screenshot.c rename to src/interface/screenshot.c index 240745c906..5f871f609b 100644 --- a/src/screenshot.c +++ b/src/interface/screenshot.c @@ -19,19 +19,18 @@ *****************************************************************************/ #pragma pack(1) -#include -#include -#include "osinterface.h" -#include "addresses.h" -#include "config.h" -#include "gfx.h" -#include "game.h" -#include "rct2.h" -#include "screenshot.h" -#include "string_ids.h" -#include "window_error.h" - #include // For MAX_PATH +#include +#include +#include "../platform/osinterface.h" +#include "../addresses.h" +#include "../config.h" +#include "../drawing/drawing.h" +#include "../game.h" +#include "../localisation/localisation.h" +#include "../windows/error.h" +#include "screenshot.h" + static int screenshot_dump_bmp(); diff --git a/src/screenshot.h b/src/interface/screenshot.h similarity index 100% rename from src/screenshot.h rename to src/interface/screenshot.h diff --git a/src/viewport.c b/src/interface/viewport.c similarity index 97% rename from src/viewport.c rename to src/interface/viewport.c index d39bf92a8d..56171dd8fa 100644 --- a/src/viewport.c +++ b/src/interface/viewport.c @@ -19,13 +19,13 @@ *****************************************************************************/ #include -#include "addresses.h" -#include "config.h" -#include "gfx.h" -#include "map.h" -#include "string_ids.h" -#include "sprite.h" -#include "sprites.h" +#include "../addresses.h" +#include "../config.h" +#include "../drawing/drawing.h" +#include "../localisation/localisation.h" +#include "../sprites.h" +#include "../world/map.h" +#include "../world/sprite.h" #include "viewport.h" #include "window.h" @@ -281,7 +281,7 @@ void viewport_update_position(rct_window *window) if (window->viewport_target_sprite != -1){ rct_sprite* sprite = &g_sprite_list[window->viewport_target_sprite]; - int height = map_element_height(0xFFFF & sprite->unknown.x, 0xFFFF & sprite->unknown.y) - 16; + int height = map_element_height(0xFFFF & sprite->unknown.x, 0xFFFF & sprite->unknown.y) & 0xFFFF - 16; int underground = sprite->unknown.z < height; RCT2_CALLPROC_X(0x6E7A15, sprite->unknown.x, sprite->unknown.y, sprite->unknown.z, underground, (int)window, (int)viewport, 0); @@ -1088,3 +1088,27 @@ void viewport_set_visibility(uint8 mode) window_invalidate(window); } } + +/** + * + * rct2: 0x00685ADC + * screenX: eax + * screenY: ebx + * flags: edx + * x: ax + * y: cx + * z: bl + * mapElement: edx + */ +void get_map_coordinates_from_pos(int screenX, int screenY, int flags, int *x, int *y, int *z, rct_map_element **mapElement) +{ + int eax, ebx, ecx, edx, esi, edi, ebp; + eax = screenX; + ebx = screenY; + edx = flags; + RCT2_CALLFUNC_X(0x00685ADC, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + if (x != NULL) *x = *((uint16*)&eax); + if (y != NULL) *y = *((uint16*)&ecx); + if (z != NULL) *z = *((uint8*)&ebx); + if (mapElement != NULL) *mapElement = (rct_map_element*)edx; +} \ No newline at end of file diff --git a/src/viewport.h b/src/interface/viewport.h similarity index 95% rename from src/viewport.h rename to src/interface/viewport.h index dfbcfb8c5c..c1dbd0c7c8 100644 --- a/src/viewport.h +++ b/src/interface/viewport.h @@ -65,4 +65,6 @@ void show_construction_rights(); void hide_construction_rights(); void viewport_set_visibility(uint8 mode); +void get_map_coordinates_from_pos(int screenX, int screenY, int flags, int *x, int *y, int *z, rct_map_element **mapElement); + #endif diff --git a/src/widget.c b/src/interface/widget.c similarity index 99% rename from src/widget.c rename to src/interface/widget.c index 003e86597a..08a7a7b554 100644 --- a/src/widget.c +++ b/src/interface/widget.c @@ -21,9 +21,9 @@ #include #include #include -#include "addresses.h" -#include "gfx.h" -#include "sprites.h" +#include "../addresses.h" +#include "../drawing/drawing.h" +#include "../sprites.h" #include "widget.h" #include "window.h" @@ -442,6 +442,7 @@ static void widget_text_unknown(rct_drawpixelinfo *dpi, rct_window *w, int widge widget->right - widget->left - 2 ); } else { + colour &= ~(1 << 7); if (widget_is_disabled(w, widgetIndex)) colour |= 0x40; gfx_draw_string_centred_clipped( @@ -808,6 +809,9 @@ static void widget_scroll_draw(rct_drawpixelinfo *dpi, rct_window *w, int widget if (scroll->flags & VSCROLLBAR_VISIBLE) r -= 11; + b++; + r++; + // Create a new inner scroll dpi scroll_dpi = *dpi; diff --git a/src/widget.h b/src/interface/widget.h similarity index 100% rename from src/widget.h rename to src/interface/widget.h diff --git a/src/window.c b/src/interface/window.c similarity index 91% rename from src/window.c rename to src/interface/window.c index af22ebfc4a..44abfc78f9 100644 --- a/src/window.c +++ b/src/interface/window.c @@ -19,17 +19,16 @@ *****************************************************************************/ #include -#include "addresses.h" -#include "audio.h" -#include "game.h" -#include "gfx.h" -#include "map.h" -#include "osinterface.h" -#include "rct2.h" +#include "../addresses.h" +#include "../audio/audio.h" +#include "../game.h" +#include "../drawing/drawing.h" +#include "../platform/osinterface.h" +#include "../world/map.h" +#include "../world/sprite.h" #include "widget.h" #include "window.h" #include "viewport.h" -#include "sprite.h" #define RCT2_FIRST_WINDOW (RCT2_ADDRESS(RCT2_ADDRESS_WINDOW_LIST, rct_window)) #define RCT2_LAST_WINDOW (RCT2_GLOBAL(RCT2_ADDRESS_NEW_WINDOW_PTR, rct_window*) - 1) @@ -39,6 +38,28 @@ rct_window* g_window_list = RCT2_ADDRESS(RCT2_ADDRESS_WINDOW_LIST, rct_window); +// converted from uint16 values at 0x009A41EC - 0x009A4230 +// these are percentage coordinates of the viewport to center to, if a window is obscuring a location, the next is tried +float window_scroll_locations[][2] = { + 0.5f, 0.5f, + 0.75f, 0.5f, + 0.25f, 0.5f, + 0.5f, 0.75f, + 0.5f, 0.25f, + 0.75f, 0.75f, + 0.75f, 0.25f, + 0.25f, 0.75f, + 0.25f, 0.25f, + 0.125f, 0.5f, + 0.875f, 0.5f, + 0.5f, 0.125f, + 0.5f, 0.875f, + 0.875f, 0.125f, + 0.875f, 0.875f, + 0.125f, 0.875f, + 0.125f, 0.125f, +}; + static void window_all_wheel_input(); static int window_draw_split(rct_window *w, int left, int top, int right, int bottom); @@ -234,7 +255,7 @@ static int window_wheel_input(rct_window *w, int wheel) continue; // Originally always checked first scroll view, bug maybe? - scroll = &w->scrolls[i * sizeof(rct_scroll)]; + scroll = &w->scrolls[i]; if (scroll->flags & (HSCROLLBAR_VISIBLE | VSCROLLBAR_VISIBLE)) { window_scroll_wheel_input(w, i, wheel); return 1; @@ -308,7 +329,7 @@ static void window_all_wheel_input() if (widgetIndex != -1) { widget = &w->widgets[widgetIndex]; if (widget->type == WWT_SCROLL) { - scroll = &w->scrolls[RCT2_GLOBAL(0x01420075, uint8) * sizeof(rct_scroll)]; + scroll = &w->scrolls[RCT2_GLOBAL(0x01420075, uint8)]; if (scroll->flags & (HSCROLLBAR_VISIBLE | VSCROLLBAR_VISIBLE)) { window_scroll_wheel_input(w, window_get_scroll_index(w, widgetIndex), wheel); return; @@ -383,7 +404,7 @@ rct_window *window_create(int x, int y, int width, int height, uint32 *event_han // Play sounds and flash the window if (!(flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT))){ w->flags |= WF_WHITE_BORDER_MASK; - sound_play_panned(SOUND_WINDOW_OPEN, x + (width / 2)); + sound_play_panned(SOUND_WINDOW_OPEN, x + (width / 2), 0, 0, 0); } w->number = 0; @@ -658,7 +679,8 @@ void window_invalidate(rct_window *window) /** * * rct2: 0x006EC3AC - * + * See also widget_invalidate that will probably be used + * when cls is > 0x7F. * @param cls (ax) * @param number (bx) */ @@ -719,6 +741,7 @@ void window_init_scroll_widgets(rct_window *w) } scroll = &w->scrolls[scroll_index]; + scroll->flags = 0; window_get_scroll_size(w, scroll_index, &width, &height); scroll->h_left = 0; scroll->h_right = width + 1; @@ -951,12 +974,87 @@ void window_scroll_to_viewport(rct_window *w) } /** - * - * rct2: 0x006E7C9C - */ +* +* rct2: 0x006E7C9C +* @param w (esi) +* @param x (eax) +* @param y (ecx) +* @param z (edx) +*/ void window_scroll_to_location(rct_window *w, int x, int y, int z) { - RCT2_CALLPROC_X(0x006E7C9C, x, 0, y, z, (int)w, 0, 0); + if (w->viewport) { + sint16 height = map_element_height(x, y); + if (z < height - 16) { + if (!(w->viewport->flags & 1 << 0)) { + w->viewport->flags |= 1 << 0; + window_invalidate(w); + } + } else { + if (w->viewport->flags & 1 << 0) { + w->viewport->flags &= ~(1 << 0); + window_invalidate(w); + } + } + sint16 sx; + sint16 sy; + switch (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8)) { + case 0: + sx = y - x; + sy = ((x + y) / 2) - z; + break; + case 1: + sx = -y - x; + sy = ((-x + y) / 2) - z; + break; + case 2: + sx = -y + x; + sy = ((-x - y) / 2) - z; + break; + case 3: + sx = y + x; + sy = ((x - y) / 2) - z; + break; + } + int i = 0; + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TITLE_DEMO)) { + int found = 0; + while (!found) { + sint16 x2 = w->viewport->x + (sint16)(w->viewport->width * window_scroll_locations[i][0]); + sint16 y2 = w->viewport->y + (sint16)(w->viewport->height * window_scroll_locations[i][1]); + rct_window* w2 = w; + while (1) { + w2++; + if (w2 >= RCT2_GLOBAL(RCT2_ADDRESS_NEW_WINDOW_PTR, rct_window*)) { + found = 1; + break; + } + sint16 x1 = w2->x - 10; + sint16 y1 = w2->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 = 0; + break; + } + } + } + if (i >= countof(window_scroll_locations)) { + i = 0; + found = 1; + } + } + } + // rct2: 0x006E7C76 + if (w->viewport_target_sprite == -1) { + if (!(w->flags & WF_2)) { + w->saved_view_x = sx - (sint16)(w->viewport->view_width * window_scroll_locations[i][0]); + w->saved_view_y = sy - (sint16)(w->viewport->view_height * window_scroll_locations[i][1]); + w->flags |= WF_SCROLLING_TO_LOCATION; + } + } + } } /** @@ -1232,8 +1330,8 @@ void window_draw_widgets(rct_window *w, rct_drawpixelinfo *dpi) widgetIndex = 0; for (widget = w->widgets; widget->type != WWT_LAST; widget++) { // Check if widget is outside the draw region - if (w->x + widget->left < dpi->x + dpi->width && w->x + widget->right > dpi->x) - if (w->y + widget->top < dpi->y + dpi->height && w->y + widget->bottom > dpi->y) + if (w->x + widget->left < dpi->x + dpi->width && w->x + widget->right >= dpi->x) + if (w->y + widget->top < dpi->y + dpi->height && w->y + widget->bottom >= dpi->y) widget_draw(dpi, w, widgetIndex); widgetIndex++; @@ -1575,13 +1673,13 @@ void RCT2_CALLPROC_WE_MOUSE_DOWN(int address, int widgetIndex, rct_window*w, rc } /* Based on rct2: 0x6987ED and another version from window_park */ -void window_align_tabs( rct_window *w, uint8 start_tab_id, uint8 end_tab_id ) +void window_align_tabs(rct_window *w, uint8 start_tab_id, uint8 end_tab_id) { - int x = w->widgets[start_tab_id].left; + int i, x = w->widgets[start_tab_id].left; int tab_width = w->widgets[start_tab_id].right - w->widgets[start_tab_id].left; - for (int i = start_tab_id; i < end_tab_id; ++i){ - if ( !(w->disabled_widgets & (1LL << i)) ){ + for (i = start_tab_id; i <= end_tab_id; i++) { + if (!(w->disabled_widgets & (1LL << i))) { w->widgets[i].left = x; w->widgets[i].right = x + tab_width; x += tab_width + 1; @@ -1589,3 +1687,14 @@ void window_align_tabs( rct_window *w, uint8 start_tab_id, uint8 end_tab_id ) } } +/** + * + * rct2: 0x006CBCC3 + */ +void window_close_construction_windows() +{ + window_close_by_id(WC_RIDE_CONSTRUCTION, 0); + window_close_by_id(WC_FOOTPATH, 0); + window_close_by_id(WC_TRACK_DESIGN_LIST, 0); + window_close_by_id(WC_TRACK_DESIGN_PLACE, 0); +} \ No newline at end of file diff --git a/src/window.h b/src/interface/window.h similarity index 80% rename from src/window.h rename to src/interface/window.h index 0270e5cdc3..1242215e0d 100644 --- a/src/window.h +++ b/src/interface/window.h @@ -21,10 +21,11 @@ #ifndef _WINDOW_H_ #define _WINDOW_H_ -#include "gfx.h" -#include "park.h" -#include "peep.h" -#include "rct2.h" +#include "../common.h" +#include "../drawing/drawing.h" +#include "../peep/peep.h" +#include "../ride/ride.h" +#include "../world/park.h" struct rct_window; union rct_window_event; @@ -104,7 +105,7 @@ typedef struct{ sint16 y; //0x484 & VIEWPORT_FOCUS_Y_MASK sint16 z; //0x486 uint8 rotation;//0x488 - uint8 pad_489; + uint8 zoom;//0x489 } coordinate_focus; // Type is viewport_target_sprite_id & 0x80000000 != 0 @@ -115,7 +116,7 @@ typedef struct{ uint8 type; //0x485 & VIEWPORT_FOCUS_TYPE_MASK uint16 pad_486; uint8 rotation; //0x488 - uint8 pad_489; + uint8 zoom; //0x489 } sprite_focus; #define VIEWPORT_FOCUS_TYPE_MASK 0xC0 @@ -123,7 +124,7 @@ enum{ VIEWPORT_FOCUS_TYPE_COORDINATE = (1<<6), VIEWPORT_FOCUS_TYPE_SPRITE = (1<<7) }; -#define VIEWPORT_FOCUS_Y_MASK 0x3FFF; +#define VIEWPORT_FOCUS_Y_MASK 0x3FFF typedef struct{ @@ -158,8 +159,9 @@ typedef struct{ } map_variables; typedef struct { - sint16 var_480; + sint16 view; sint32 var_482; + sint32 var_486; } ride_variables; typedef struct { @@ -167,6 +169,16 @@ typedef struct { sint16 hover_counter; } scenery_variables; +typedef struct { + uint16 var_480; + uint16 var_482; + uint16 var_484; +} track_list_variables; + +typedef struct { + uint16 var_480; +} error_variables; + /** * Window structure * size: 0x4C0 @@ -205,6 +217,8 @@ typedef struct rct_window { map_variables map; ride_variables ride; scenery_variables scenery; + track_list_variables track_list; + error_variables error; }; sint16 page; // 0x48A sint16 var_48C; @@ -234,7 +248,12 @@ typedef enum { WE_RESIZE = 2, WE_MOUSE_DOWN = 3, WE_DROPDOWN = 4, - WE_UNKNOWN_05 = 5, + WE_UNKNOWN_05 = 5, + // Unknown 05: Used to update tabs that are not being animated + // see window_peep. When the overview tab is not highlighted the + // items being carried such as hats/balloons still need to be shown + // and removed. Probably called after anything that affects items + // being carried. WE_UPDATE = 6, WE_UNKNOWN_07 = 7, WE_UNKNOWN_08 = 8, @@ -330,14 +349,15 @@ enum { WC_TOOLTIP = 5, WC_DROPDOWN = 6, WC_ABOUT = 8, - WC_MUSIC_CREDITS = 9, - WC_PUBLISHER_CREDITS = 10, + WC_PUBLISHER_CREDITS = 9, + WC_MUSIC_CREDITS = 10, WC_ERROR = 11, WC_RIDE = 12, WC_RIDE_CONSTRUCTION = 13, WC_SAVE_PROMPT = 14, WC_RIDE_LIST = 15, WC_CONSTRUCT_RIDE = 16, + WC_DEMOLISH_RIDE_PROMPT = 17, WC_SCENERY = 18, WC_OPTIONS = 19, WC_FOOTPATH = 20, @@ -354,6 +374,7 @@ enum { WC_RECENT_NEWS = 31, WC_SCENARIO_SELECT = 32, WC_TRACK_DESIGN_LIST = 33, + WC_TRACK_DESIGN_PLACE = 34, WC_NEW_CAMPAIGN = 35, WC_KEYBOARD_SHORTCUT_LIST = 36, WC_CHANGE_KEYBOARD_SHORTCUT = 37, @@ -364,6 +385,8 @@ enum { WC_EDITOR_INVENTION_LIST = 43, WC_EDITOR_SCENARIO_OPTIONS = 45, WC_EDTIOR_OBJECTIVE_OPTIONS = 46, + WC_47, + WC_48, WC_CLEAR_SCENERY = 50, WC_MANAGE_TRACK_DESIGN = 89, WC_CHEATS = 110, @@ -380,6 +403,9 @@ enum PROMPT_MODE { // rct2: 0x01420078 extern rct_window* g_window_list; +// rct2: 0x00F635EE +extern ride_list_item _window_track_list_item; + void window_dispatch_update_all(); void window_update_all(); rct_window *window_create(int x, int y, int width, int height, uint32 *event_handlers, rct_windowclass cls, uint16 flags); @@ -426,6 +452,8 @@ void window_set_resize(rct_window *w, int minWidth, int minHeight, int maxWidth, int tool_set(rct_window *w, int widgetIndex, int tool); void tool_cancel(); +void window_close_construction_windows(); + // Open window functions void window_main_open(); void window_resize_gui(int width, int height); @@ -440,15 +468,18 @@ void window_title_exit_open(); void window_title_logo_open(); void window_news_open(); void window_scenarioselect_open(); +void window_track_list_open(ride_list_item item); void window_clear_scenery_open(); void window_land_open(); void window_water_open(); -void window_staff_open(); +void window_staff_list_open(); void window_guest_list_open(); void window_map_open(); void window_options_open(); -void window_peep_open(rct_peep* peep); -void window_staff_peep_open(rct_peep* peep); +void window_shortcut_keys_open(); +void window_shortcut_change_open(int selected_key); +void window_guest_open(rct_peep* peep); +void window_staff_open(rct_peep* peep); void window_park_awards_open(); void window_park_entrance_open(); void window_park_guests_open(); @@ -459,11 +490,15 @@ void window_finances_research_open(); void window_new_campaign_open(sint16 campaignType); void window_ride_main_open(int rideIndex); void window_ride_list_open(); +void window_track_place_open(); void window_new_ride_open(); void window_banner_open(); void window_cheats_open(); void window_research_open(); void window_scenery_open(); +void window_music_credits_open(); +void window_publisher_credits_open(); +void window_track_manage_open(); void window_guest_list_init_vars_a(); void window_guest_list_init_vars_b(); @@ -472,8 +507,9 @@ void window_bubble_list_item(rct_window* w, int item_position); void window_align_tabs( rct_window *w, uint8 start_tab_id, uint8 end_tab_id ); void window_new_ride_init_vars(); +void window_new_ride_focus(ride_list_item rideItem); -void window_staff_init_vars(); +void window_staff_list_init_vars(); void window_event_helper(rct_window* w, short widgetIndex, WINDOW_EVENTS event); void RCT2_CALLPROC_WE_MOUSE_DOWN(int address, int widgetIndex, rct_window*w, rct_widget* widget); @@ -490,6 +526,12 @@ void RCT2_CALLPROC_WE_MOUSE_DOWN(int address, int widgetIndex, rct_window*w, rct __asm mov dropdownIndex, ax \ __asm mov widgetIndex, dx \ __asm mov w, esi + + #define window_text_input_get_registers(w, widgetIndex, _cl, text) \ + __asm mov widgetIndex, dx \ + __asm mov _cl, cl \ + __asm mov w, esi \ + __asm mov text, edi #define window_scrollmouse_get_registers(w, x, y) \ __asm mov x, cx \ @@ -502,36 +544,54 @@ void RCT2_CALLPROC_WE_MOUSE_DOWN(int address, int widgetIndex, rct_window*w, rct __asm mov widgetIndex, dx \ __asm mov w, esi + #define window_textinput_get_registers(w, widgetIndex, result, text) \ + __asm mov result, cl \ + __asm mov widgetIndex, dx \ + __asm mov w, esi \ + __asm mov text, edi + #define window_paint_get_registers(w, dpi) \ __asm mov w, esi \ __asm mov dpi, edi #else #define window_get_register(w) \ - __asm__ ( "mov %[w], esi " : [w] "+m" (w) ); + __asm__ ( "mov %["#w"], esi " : [w] "+m" (w) ); #define window_widget_get_registers(w, widgetIndex) \ - __asm__ ( "mov %[widgetIndex], dx " : [widgetIndex] "+m" (widgetIndex) ); \ - __asm__ ( "mov %[w], esi " : [w] "+m" (w) ); + __asm__ ( "mov %["#widgetIndex"], dx " : [widgetIndex] "+m" (widgetIndex) ); \ + __asm__ ( "mov %["#w"], esi " : [w] "+m" (w) ); #define window_dropdown_get_registers(w, widgetIndex, dropdownIndex) \ - __asm__ ( "mov %[dropdownIndex], ax " : [dropdownIndex] "+m" (dropdownIndex) ); \ + __asm__ ( "mov %["#dropdownIndex"], ax " : [dropdownIndex] "+m" (dropdownIndex) ); \ + __asm__ ( "mov %["#widgetIndex"], dx " : [widgetIndex] "+m" (widgetIndex) ); \ + __asm__ ( "mov %["#w"], esi " : [w] "+m" (w) ); + + #define window_text_input_get_registers(w, widgetIndex, _cl, text) \ + __asm__ ( "mov %[_cl], cl " : [_cl] "+m" (_cl) ); \ __asm__ ( "mov %[widgetIndex], dx " : [widgetIndex] "+m" (widgetIndex) ); \ - __asm__ ( "mov %[w], esi " : [w] "+m" (w) ); + __asm__ ( "mov %[w], esi " : [w] "+m" (w) ); \ + __asm__ ( "mov %[text], edi " : [text] "+m" (text) ); #define window_scrollmouse_get_registers(w, x, y) \ - __asm__ ( "mov %[x], cx " : [x] "+m" (x) ); \ - __asm__ ( "mov %[y], dx " : [y] "+m" (y) ); \ - __asm__ ( "mov %[w], esi " : [w] "+m" (w) ); + __asm__ ( "mov %["#x"], cx " : [x] "+m" (x) ); \ + __asm__ ( "mov %["#y"], dx " : [y] "+m" (y) ); \ + __asm__ ( "mov %["#w"], esi " : [w] "+m" (w) ); #define window_tool_get_registers(w, widgetIndex, x, y) \ - __asm__ ( "mov %[x], ax " : [x] "+m" (x) ); \ - __asm__ ( "mov %[y], bx " : [y] "+m" (y) ); \ + __asm__ ( "mov %["#x"], ax " : [x] "+m" (x) ); \ + __asm__ ( "mov %["#y"], bx " : [y] "+m" (y) ); \ + __asm__ ( "mov %["#widgetIndex"], dx " : [widgetIndex] "+m" (widgetIndex) ); \ + __asm__ ( "mov %["#w"], esi " : [w] "+m" (w) ); + + #define window_textinput_get_registers(w, widgetIndex, result, text) \ + __asm__ ( "mov %[result], cl " : [result] "+m" (result) ); \ __asm__ ( "mov %[widgetIndex], dx " : [widgetIndex] "+m" (widgetIndex) ); \ - __asm__ ( "mov %[w], esi " : [w] "+m" (w) ); + __asm__ ( "mov %[w], esi " : [w] "+m" (w) ); \ + __asm__ ( "mov %[text], edi " : [text] "+m" (text) ); #define window_paint_get_registers(w, dpi) \ - __asm__ ( "mov %[w], esi " : [w] "+m" (w) ); \ - __asm__ ( "mov %[dpi], edi " : [dpi] "+m" (dpi) ); + __asm__ ( "mov %["#w"], esi " : [w] "+m" (w) ); \ + __asm__ ( "mov %["#dpi"], edi " : [dpi] "+m" (dpi) ); #endif #endif diff --git a/src/intro.c b/src/intro.c index 8b2ee2fdba..17f22c2ce0 100644 --- a/src/intro.c +++ b/src/intro.c @@ -19,13 +19,12 @@ *****************************************************************************/ #include "addresses.h" -#include "audio.h" -#include "gfx.h" +#include "audio/audio.h" +#include "drawing/drawing.h" #include "intro.h" -#include "rct2.h" -#include "osinterface.h" +#include "localisation/localisation.h" +#include "platform/osinterface.h" #include "sprites.h" -#include "string_ids.h" static void screen_intro_process_mouse_input(); static void screen_intro_process_keyboard_input(); diff --git a/src/currency.c b/src/localisation/currency.c similarity index 100% rename from src/currency.c rename to src/localisation/currency.c diff --git a/src/currency.h b/src/localisation/currency.h similarity index 100% rename from src/currency.h rename to src/localisation/currency.h diff --git a/src/date.c b/src/localisation/date.c similarity index 97% rename from src/date.c rename to src/localisation/date.c index 1db9d0f224..8312f5d798 100644 --- a/src/date.c +++ b/src/localisation/date.c @@ -18,9 +18,8 @@ * along with this program. If not, see . *****************************************************************************/ -#include "addresses.h" +#include "../addresses.h" #include "date.h" -#include "rct2.h" // rct2: 0x00993988 const sint16 days_in_month[MONTH_COUNT] = { 31, 30, 31, 30, 31, 31, 30, 31 }; diff --git a/src/date.h b/src/localisation/date.h similarity index 98% rename from src/date.h rename to src/localisation/date.h index 0fef3dde69..94d0f3af4c 100644 --- a/src/date.h +++ b/src/localisation/date.h @@ -21,7 +21,7 @@ #ifndef _DATE_H_ #define _DATE_H_ -#include "rct2.h" +#include "../common.h" enum { MONTH_MARCH, diff --git a/src/localisation/format_codes.h b/src/localisation/format_codes.h new file mode 100644 index 0000000000..c0931c0b4b --- /dev/null +++ b/src/localisation/format_codes.h @@ -0,0 +1,127 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of OpenRCT2. + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#ifndef _FORMAT_CODES_H_ +#define _FORMAT_CODES_H_ + +char format_get_code(const char *token); +const char *format_get_token(char code); + +enum { + // Font format codes + + // The next byte specifies the X coordinate + FORMAT_MOVE_X = 1, + // The next byte specifies the palette + FORMAT_ADJUST_PALETTE, + + // Moves to the next line + FORMAT_NEWLINE = 5, + // Moves less than NEWLINE + FORMAT_NEWLINE_SMALLER, + + FORMAT_TINYFONT, + FORMAT_BIGFONT, + FORMAT_MEDIUMFONT, + FORMAT_SMALLFONT, + + FORMAT_OUTLINE, + FORMAT_OUTLINE_OFF, + + // Changes the colour of the text to a predefined window colour. + FORMAT_WINDOW_COLOUR_1, + FORMAT_WINDOW_COLOUR_2, + FORMAT_WINDOW_COLOUR_3, + + // The next 2 bytes specify the X and Y coordinates + FORMAT_NEWLINE_X_Y = 17, + + // The next 4 bytes specify the sprite + FORMAT_INLINE_SPRITE = 23, + + // Non ascii-characters + FORMAT_ENDQUOTES = 34, + + // Argument format codes + FORMAT_ARGUMENT_CODE_START = 123, + FORMAT_COMMA32 = 123, + FORMAT_INT32, + FORMAT_COMMA2DP32, + FORMAT_COMMA16, + FORMAT_UINT16, + FORMAT_CURRENCY2DP, + FORMAT_CURRENCY, + FORMAT_STRINGID, + FORMAT_STRINGID2, + FORMAT_STRING, + FORMAT_MONTHYEAR, + FORMAT_MONTH, + FORMAT_VELOCITY, + FORMAT_POP16, + FORMAT_PUSH16, + FORMAT_DURATION, + FORMAT_REALTIME, + FORMAT_LENGTH, + FORMAT_SPRITE, + + // Colour format codes + FORMAT_COLOUR_CODE_START = 142, + FORMAT_BLACK = 142, + FORMAT_GREY, + FORMAT_WHITE, + FORMAT_RED, + FORMAT_GREEN, + FORMAT_YELLOW, + FORMAT_TOPAZ, + FORMAT_CELADON, + FORMAT_BABYBLUE, + FORMAT_PALELAVENDER, + FORMAT_PALEGOLD, + FORMAT_LIGHTPINK, + FORMAT_PEARLAQUA, + FORMAT_PALESILVER, + FORMAT_COLOUR_CODE_END = FORMAT_PALESILVER, + + // Extra non-ascii characters + FORMAT_AMINUSCULE = 159, + FORMAT_UP, + FORMAT_POUND = 163, + FORMAT_YEN = 165, + FORMAT_COPYRIGHT = 169, + FORMAT_DOWN, + FORMAT_LEFTGUILLEMET, + FORMAT_TICK, + FORMAT_CROSS, + FORMAT_RIGHT = 175, + FORMAT_DEGREE, + FORMAT_SQUARED = 178, + FORMAT_OPENQUOTES = 180, + FORMAT_EURO = 181, + FORMAT_APPROX = 184, + FORMAT_POWERNEGATIVEONE, + FORMAT_BULLET, + FORMAT_RIGHTGUILLEMET, + FORMAT_SMALLUP, + FORMAT_SMALLDOWN, + FORMAT_LEFT, + FORMAT_INVERTEDQUESTION +}; + +#endif \ No newline at end of file diff --git a/src/language.c b/src/localisation/language.c similarity index 96% rename from src/language.c rename to src/localisation/language.c index a276a30b6d..c0951caf74 100644 --- a/src/language.c +++ b/src/localisation/language.c @@ -20,9 +20,8 @@ #include #include -#include "addresses.h" -#include "language.h" -#include "string_ids.h" +#include "../addresses.h" +#include "localisation.h" const char *language_names[LANGUAGE_COUNT] = { "", // LANGUAGE_UNDEFINED @@ -32,7 +31,8 @@ const char *language_names[LANGUAGE_COUNT] = { "Fran\u00E7ais", // LANGUAGE_FRENCH "Magyar", // LANGUAGE_HUNGARIAN "Polski", // LANGUAGE_POLISH - "Espa\u00F1ol" // LANGUAGE_SPANISH + "Espa\u00F1ol", // LANGUAGE_SPANISH + "Svenska" // LANGUAGE_SWEDISH }; const char *language_filenames[LANGUAGE_COUNT] = { @@ -43,7 +43,8 @@ const char *language_filenames[LANGUAGE_COUNT] = { "french", // LANGUAGE_FRENCH "hungarian", // LANGUAGE_HUNGARIAN "polish", // LANGUAGE_POLISH - "spanish_sp" // LANGUAGE_SPANISH + "spanish_sp", // LANGUAGE_SPANISH + "swedish" // LANGUAGE_SWEDISH }; int gCurrentLanguage = LANGUAGE_UNDEFINED; @@ -132,7 +133,8 @@ static int language_open_file(const char *filename) language_strings = calloc(STR_COUNT, sizeof(char*)); - char *dst, *token; + char *dst = NULL; + char *token = NULL; char tokenBuffer[64]; int i, stringIndex = 0, mode = 0, string_no; for (i = 0; i < language_buffer_size; i++) { diff --git a/src/language.h b/src/localisation/language.h similarity index 96% rename from src/language.h rename to src/localisation/language.h index 17e4dac8f5..88fa6e5a9c 100644 --- a/src/language.h +++ b/src/localisation/language.h @@ -21,8 +21,7 @@ #ifndef _LANGUAGE_H_ #define _LANGUAGE_H_ -#include "rct2.h" -#include "string_ids.h" +#include "../common.h" enum { LANGUAGE_UNDEFINED, @@ -33,6 +32,7 @@ enum { LANGUAGE_HUNGARIAN, LANGUAGE_POLISH, LANGUAGE_SPANISH, + LANGUAGE_SWEDISH, LANGUAGE_COUNT }; diff --git a/src/string_ids.c b/src/localisation/localisation.c similarity index 56% rename from src/string_ids.c rename to src/localisation/localisation.c index bbd2b709cf..c2462bbd1a 100644 --- a/src/string_ids.c +++ b/src/localisation/localisation.c @@ -18,1053 +18,12 @@ * along with this program. If not, see . *****************************************************************************/ -#include -#include -#include "addresses.h" -#include "config.h" -#include "currency.h" -#include "game.h" +#include "../addresses.h" +#include "../config.h" +#include "../game.h" +#include "../util/util.h" #include "date.h" -#include "language.h" -#include "rct2.h" -#include "string_ids.h" -#include "util.h" - -// TODO Store real names in a data file. -#pragma region Real names - -const char *real_names[] = { - "Aaron", - "Abdul", - "Abraham", - "Abu", - "Adam", - "Adrian", - "Adriane", - "Aileen", - "Aisha", - "Akiko", - "Akira", - "Al", - "Ali", - "Alan", - "Alana", - "Albert", - "Alberta", - "Alec", - "Alesia", - "Alex", - "Alexa", - "Alexander", - "Alexandra", - "Alexis", - "Alf", - "Alfonso", - "Alfred", - "Alice", - "Alicia", - "Alison", - "Alistair", - "Allan", - "Allen", - "Allison", - "Allister", - "Alma", - "Alvin", - "Alyson", - "Amanda", - "Amber", - "Amilio", - "Amos", - "Amy", - "Ana", - "Anabel", - "Anastasia", - "Andie", - "Andrea", - "Andres", - "Andrew", - "Andy", - "Angel", - "Angela", - "Angelica", - "Angie", - "Angus", - "Anika", - "Ann", - "Anna", - "Anne", - "Annette", - "Annie", - "Annika", - "Anthony", - "Anton", - "Antonio", - "April", - "Archer", - "Archie", - "Arlene", - "Arnie", - "Arnold", - "Art", - "Arthur", - "Asaf", - "Ashley", - "Astrid", - "Aubrey", - "Austin", - "Austine", - "Avon", - "Avril", - "Axel", - "Aziz", - "Bailey", - "Barbara", - "Barney", - "Barry", - "Bart", - "Barton", - "Baxter", - "Beck", - "Becket", - "Becky", - "Belinda", - "Bella", - "Belle", - "Ben", - "Benjamin", - "Benny", - "Bernadette", - "Bernard", - "Bernice", - "Bess", - "Beth", - "Bethany", - "Bette", - "Betty", - "Bernard", - "Bernardette", - "Bernice", - "Berty", - "Bev", - "Beverly", - "Beverley", - "Bianca", - "Bill", - "Billie", - "Billy", - "Bjorn", - "Blaire", - "Blake", - "Blanche", - "Bo", - "Bob", - "Bobbie", - "Bobby", - "Bonnie", - "Boris", - "Brad", - "Bradley", - "Brady", - "Brandi", - "Brandon", - "Brandy", - "Brenda", - "Brendan", - "Brendon", - "Brent", - "Brett", - "Brian", - "Bridgit", - "Brigitte", - "Britney", - "Bruce", - "Bruno", - "Brutus", - "Bryan", - "Buck", - "Bucky", - "Bug", - "Burton", - "Byron", - "Cailin", - "Caitlyn", - "Cal", - "Caley", - "Callum", - "Calvin", - "Cameron", - "Camille", - "Campbell", - "Candy", - "Carl", - "Carla", - "Carlene", - "Carlos", - "Carmela", - "Carmen", - "Carol", - "Carole", - "Caroline", - "Carolyn", - "Carrie", - "Casey", - "Cassandra", - "Cassey", - "Cassie", - "Catherina", - "Catherine", - "Cathy", - "Caz", - "Cecelia", - "Cecil", - "Cecille", - "Ceilidh", - "Celeste", - "Chad", - "Charlene", - "Charles", - "Charlie", - "Charlotte", - "Chelsea", - "Cher", - "Cheri", - "Cheryll", - "Chip", - "Chloe", - "Chris", - "Christel", - "Christian", - "Christie", - "Christina", - "Christine", - "Christopher", - "Chuck", - "Cindy", - "Clark", - "Clair", - "Claire", - "Clara", - "Clarabell", - "Claude", - "Claudette", - "Claudia", - "Clayton", - "Cliff", - "Clifford", - "Clint", - "Clive", - "Clyde", - "Codey", - "Cody", - "Colin", - "Colleen", - "Connie", - "Coral", - "Corina", - "Craig", - "Curtis", - "Cynthia", - "Cyril", - "Darby", - "Daisy", - "Dale", - "Damien", - "Damon", - "Dan", - "Dana", - "Daniel", - "Danielle", - "Danni", - "Danny", - "Daphne", - "Darla", - "Darlene", - "Darrell", - "Darren", - "Darryl", - "Dave", - "David", - "Davie", - "Davis", - "Dawn", - "Dean", - "Debbie", - "Debby", - "Deborah", - "Debra", - "Debs", - "Deidre", - "Delores", - "Denise", - "Dennis", - "Denzel", - "Derek", - "Desmond", - "Diana", - "Diane", - "Dianna", - "Dick", - "Dillon", - "Dina", - "Dominic", - "Dominik", - "Don", - "Donald", - "Donna", - "Donovan", - "Doreen", - "Doris", - "Dorothy", - "Doug", - "Dougal", - "Douglas", - "Doyle", - "Drew", - "Duane", - "Dudley", - "Duncan", - "Dwight", - "Dylan", - "Earl", - "Ed", - "Eddie", - "Edgar", - "Edith", - "Edmond", - "Edward", - "Edwin", - "Edwina", - "Eileen", - "Elaine", - "Elina", - "Elisa", - "Elisabeth", - "Eliza", - "Elizabeth", - "Ella", - "Ellen", - "Elmer", - "Elsie", - "Emile", - "Emilio", - "Emily", - "Emma", - "Emmett", - "Enrique", - "Eric", - "Erica", - "Ericka", - "Erik", - "Erika", - "Erin", - "Erinn", - "Ernest", - "Esmeralda", - "Esta", - "Estella", - "Esther", - "Ethan", - "Eugene", - "Eva", - "Evan", - "Eve", - "Evelyn", - "Everett", - "Felix", - "Fabio", - "Falicia", - "Farah", - "Felicity", - "Fernando", - "Fergus", - "Fidelia", - "Finlay", - "Fiona", - "Fletcher", - "Flora", - "Florence", - "Floyd", - "Fly", - "Frances", - "Francesca", - "Francis", - "Francisco", - "Frank", - "Franklin", - "Franky", - "Fraser", - "Fred", - "Freda", - "Freddy", - "Fuzz", - "Gabriel", - "Gabriela", - "Gail", - "Garrett", - "Garth", - "Gary", - "Gavin", - "Gayle", - "Gene", - "Genevieve", - "Geoff", - "Geoffrey", - "George", - "Gerald", - "Geraldine", - "Gerard", - "Geri", - "Gerry", - "Gilbert", - "Gillian", - "Gina", - "Ginger", - "Giuseppe", - "Gladys", - "Glen", - "Glenda", - "Glenn", - "Gloria", - "Glyne", - "Goldie", - "Gordon", - "Grace", - "Graeme", - "Graham", - "Grant", - "Grayson", - "Greg", - "Gregor", - "Gregory", - "Gretchen", - "Gus", - "Guy", - "Gwen", - "Gwendoline", - "Hadrian", - "Hamish", - "Hank", - "Hannah", - "Hans", - "Harley", - "Harold", - "Harry", - "Harvey", - "Haseem", - "Hayley", - "Hazel", - "Heather", - "Hector", - "Heidi", - "Helen", - "Helena", - "Henri", - "Henry", - "Herbert", - "Herbie", - "Hermann", - "Hilda", - "Hollie", - "Holly", - "Homer", - "Horace", - "Howard", - "Hugh", - "Hugo", - "Iain", - "Ian", - "Imani", - "Imelda", - "Imran", - "Ingrid", - "Irene", - "Irma", - "Irving", - "Isaac", - "Isabella", - "Isabelle", - "Ishan", - "Isla", - "Ivan", - "Ivanna", - "Ivy", - "Izola", - "Jack", - "Jacque", - "Jacqueline", - "Jacqui", - "Jake", - "Jakob", - "James", - "Jacob", - "Jan", - "Janet", - "Jane", - "Janice", - "Jason", - "Jasper", - "Jay", - "Jayne", - "Jean", - "Jeanette", - "Jeff", - "Jeffrey", - "Jennifer", - "Jenny", - "Jeremy", - "Jerry", - "Jesse", - "Jessica", - "Jessie", - "Jessy", - "Jill", - "Jillian", - "Jim", - "Jimbo", - "Jimmy", - "Jo", - "Joan", - "Joann", - "Joanne", - "Jock", - "Jodi", - "Joe", - "Joel", - "Joelyn", - "Joey", - "Johan", - "John", - "Johnathan", - "Johnnie", - "Johnny", - "Jolynn", - "Jon", - "Jonah", - "Jonas", - "Jonathan", - "Joni", - "Jonny", - "Jordan", - "Jorge", - "Jose", - "Joseph", - "Josephine", - "Josh", - "Joshua", - "Joyce", - "Juan", - "Juana", - "Juanita", - "Judge", - "Judie", - "Judith", - "Judy", - "Julia", - "Julian", - "Julie", - "Juliette", - "Julio", - "Julius", - "June", - "Justin", - "Kaley", - "Kaitlyn", - "Kandice", - "Kara", - "Kareen", - "Karen", - "Karl", - "Karolyne", - "Karri", - "Kate", - "Katelyn", - "Katey", - "Kathy", - "Katherine", - "Kathie", - "Kathleen", - "Kathryn", - "Katie", - "Katrina", - "Katy", - "Katya", - "Kay", - "Keiko", - "Keith", - "Kelly", - "Kelsey", - "Ken", - "Kenneth", - "Kenny", - "Kerry", - "Kev", - "Kevin", - "Kieran", - "Kim", - "Kimberly", - "Kiriaki", - "Kirk", - "Klaus", - "Kris", - "Krista", - "Kristian", - "Kristy", - "Kurt", - "Kurtis", - "Kyle", - "Kylie", - "Laila", - "Lana", - "Lance", - "Larry", - "Lasse", - "Latisha", - "Laura", - "Lauren", - "Lauryn", - "Laurie", - "Lawrence", - "Leah", - "Lee", - "Leigh", - "Len", - "Lena", - "Lenore", - "Leo", - "Leon", - "Leonard", - "Leonardo", - "Leone", - "Leroy", - "Les", - "Leslie", - "Lesley", - "Lester", - "Lewis", - "Liam", - "Lillian", - "Lilly", - "Lily", - "Linda", - "Lindsay", - "Lindsey", - "Lisa", - "Lita", - "Logan", - "Lone", - "Loren", - "Loretta", - "Lori", - "Lorraine", - "Lottie", - "Louis", - "Louise", - "Lowell", - "Lucas", - "Lucy", - "Luis", - "Luke", - "Luther", - "Lydia", - "Lynn", - "Lynne", - "Lyssa", - "Mabel", - "Madeline", - "Maggie", - "Magnus", - "Mahamed", - "Malcolm", - "Mandy", - "Manuel", - "Marc", - "Marcela", - "Marci", - "Marcia", - "Marco", - "Marcus", - "Marcy", - "Margaret", - "Margarita", - "Maria", - "Mariah", - "Marian", - "Marianna", - "Marie", - "Marilyn", - "Marina", - "Marion", - "Marisa", - "Marissa", - "Marjorie", - "Mark", - "Markus", - "Marlene", - "Marlin", - "Marlon", - "Marshall", - "Martha", - "Martin", - "Martyn", - "Marvin", - "Mary", - "Mathew", - "Matt", - "Matthew", - "Maude", - "Maureen", - "Maurice", - "Mauricio", - "Mavis", - "Max", - "Maxine", - "May", - "Megan", - "Meghan", - "Mel", - "Melanie", - "Melany", - "Melinda", - "Melissa", - "Melody", - "Melvin", - "Mervin", - "Mhairi", - "Mia", - "Michael", - "Michelle", - "Mick", - "Mickey", - "Miguel", - "Mikael", - "Mike", - "Mikey", - "Miki", - "Mikko", - "Mildred", - "Millie", - "Milly", - "Milton", - "Miranda", - "Miriam", - "Mirriam", - "Mitchell", - "Mo", - "Molly", - "Monica", - "Monique", - "Monty", - "Morgan", - "Morten", - "Moses", - "Morris", - "Muriel", - "Murphy", - "Murray", - "Mustafa", - "Myles", - "Myrissa", - "Myrtle", - "Nadine", - "Nancy", - "Nanette", - "Naomi", - "Natalia", - "Natalie", - "Natasha", - "Nathan", - "Nathaniel", - "Neil", - "Nellie", - "Nelly", - "Nelson", - "Neville", - "Nicholas", - "Nichole", - "Nick", - "Nico", - "Nicola", - "Nicolas", - "Nicole", - "Nigel", - "Nikia", - "Nikki", - "Nina", - "Noah", - "Noel", - "Norma", - "Norman", - "Norris", - "Norvall", - "Olga", - "Olive", - "Oliver", - "Ollie", - "Omar", - "Oona", - "Orve", - "Orville", - "Oscar", - "Otto", - "Owen", - "Paisley", - "Pam", - "Pamela", - "Pandora", - "Pat", - "Patricia", - "Patrick", - "Patty", - "Paul", - "Paula", - "Pauline", - "Pedro", - "Peggy", - "Penelope", - "Penny", - "Perry", - "Pete", - "Peter", - "Phil", - "Philip", - "Phillip", - "Phyllis", - "Polly", - "Preston", - "Qasim", - "Quentin", - "Quinn", - "Rachel", - "Rae", - "Rafael", - "Raj", - "Raja", - "Ralph", - "Ramon", - "Randal", - "Rashid", - "Raquel", - "Raul", - "Ray", - "Raymond", - "Raymondo", - "Rebecca", - "Reg", - "Regina", - "Reginald", - "Reinhold", - "Rene", - "Reuben", - "Rex", - "Rhonda", - "Richard", - "Rick", - "Ricky", - "Rita", - "Robb", - "Robert", - "Roberta", - "Robin", - "Robina", - "Robyn", - "Robynne", - "Rock", - "Rockie", - "Rod", - "Rodney", - "Rodrigo", - "Roland", - "Rolf", - "Romeo", - "Ronald", - "Ronan", - "Ronnie", - "Roger", - "Rosalind", - "Rosanna", - "Rosanned", - "Rose", - "Rosemary", - "Rosetta", - "Rosie", - "Ross", - "Roxanne", - "Roy", - "Russell", - "Rosty", - "Ruben", - "Ruby", - "Ruth", - "Ryan", - "Sabrina", - "Sadie", - "Sally", - "Sam", - "Samantha", - "Sammy", - "Samuel", - "Sandra", - "Sandy", - "Sara", - "Sarah", - "Sasha", - "Saul", - "Scot", - "Scott", - "Sean", - "Sebastian", - "Sergio", - "Shakira", - "Shannon", - "Shari", - "Sharnell", - "Sharon", - "Sharyn", - "Shawn", - "Shelby", - "Shelley", - "Sherene", - "Sheri", - "Sherman", - "Sherry", - "Shirley", - "Sheryl", - "Shivani", - "Shona", - "Sian", - "Sid", - "Sidney", - "Simon", - "Sindy", - "Sinead", - "Sofia", - "Sonny", - "Sonja", - "Sonya", - "Sophia", - "Sophie", - "Spencer", - "Stacey", - "Stan", - "Stanley", - "Stefan", - "Stephen", - "Stephanie", - "Steve", - "Steven", - "Stewart", - "Stuart", - "Sue", - "Suki", - "Susan", - "Susana", - "Susanne", - "Susie", - "Suzanne", - "Sven", - "Sylvester", - "Sylvia", - "Tabatha", - "Tamara", - "Tammie", - "Tamsin", - "Tania", - "Tanya", - "Tara", - "Taylor", - "Ted", - "Teresa", - "Terrance", - "Terry", - "Tess", - "Tessa", - "Tex", - "Thelma", - "Theodore", - "Theresa", - "Thomas", - "Tiffany", - "Tiger", - "Tiko", - "Tillie", - "Tim", - "Timmy", - "Timothy", - "Tina", - "Toby", - "Todd", - "Tom", - "Tomaki", - "Tommy", - "Tonia", - "Tonie", - "Tony", - "Tracy", - "Travis", - "Trevor", - "Tricia", - "Trixie", - "Troy", - "Tucker", - "Tyler", - "Tyson", - "Ulysses", - "Uri", - "Val", - "Valerie", - "Vanessa", - "Vani", - "Vaughn", - "Velma", - "Vernon", - "Veronica", - "Vicki", - "Vicky", - "Victor", - "Victoria", - "Vijay", - "Vince", - "Vincent", - "Vinnie", - "Virginia", - "Viv", - "Vivian", - "Viviene", - "Wally", - "Walt", - "Walter", - "Walton", - "Wanda", - "Warren", - "Wayne", - "Wendell", - "Wendy", - "Wes", - "Wesley", - "Whitney", - "Will", - "William", - "Willie", - "Willis", - "Wilson", - "Winston", - "Wyatt", - "Xavier", - "Yasmin", - "Yogi", - "Ysabel", - "Yvonne", - "Zachary", - "Zachery", - "Zola" -}; - -#pragma endregion - -char real_name_initials[] = { - 'B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'W' -}; +#include "localisation.h" #pragma region Format codes @@ -1508,7 +467,7 @@ void format_string_code(unsigned char format_code, char **dest, char **args) } format_integer(dest, value % 60); - strcpy(*dest, value % 60 == 1 ? "sec:" : "secs:"); + strcpy(*dest, value % 60 == 1 ? "sec" : "secs"); *dest += strlen(*dest); break; case FORMAT_REALTIME: @@ -1523,7 +482,7 @@ void format_string_code(unsigned char format_code, char **dest, char **args) } format_integer(dest, value % 60); - strcpy(*dest, value % 60 == 1 ? "min:" : "mins:"); + strcpy(*dest, value % 60 == 1 ? "min" : "mins"); *dest += strlen(*dest); break; case FORMAT_LENGTH: @@ -1691,4 +650,59 @@ void reset_saved_strings() { for (int i = 0; i < 1024; i++) { RCT2_ADDRESS(0x135A8F4, uint8)[i * 32] = 0; } +} + +/** +* Return the length of the string in buffer. +* note you can't use strlen as there can be inline sprites! +* +* buffer (esi) +*/ +int get_string_length(char* buffer) +{ + // Length of string + int length = 0; + + for (uint8* curr_char = (uint8*)buffer; *curr_char != (uint8)0; curr_char++) { + length++; + if (*curr_char >= 0x20) { + continue; + } + switch (*curr_char) { + case FORMAT_MOVE_X: + case FORMAT_ADJUST_PALETTE: + case 3: + case 4: + curr_char++; + length++; + break; + case FORMAT_NEWLINE: + case FORMAT_NEWLINE_SMALLER: + case FORMAT_TINYFONT: + case FORMAT_BIGFONT: + case FORMAT_MEDIUMFONT: + case FORMAT_SMALLFONT: + case FORMAT_OUTLINE: + case FORMAT_OUTLINE_OFF: + case FORMAT_WINDOW_COLOUR_1: + case FORMAT_WINDOW_COLOUR_2: + case FORMAT_WINDOW_COLOUR_3: + case 0x10: + continue; + case FORMAT_INLINE_SPRITE: + length += 4; + curr_char += 4; + break; + default: + if (*curr_char <= 0x16) { //case 0x11? FORMAT_NEW_LINE_X_Y + length += 2; + curr_char += 2; + continue; + } + length += 4; + curr_char += 4;//never happens? + break; + } + } + return length; } \ No newline at end of file diff --git a/src/localisation/localisation.h b/src/localisation/localisation.h new file mode 100644 index 0000000000..2af3b29679 --- /dev/null +++ b/src/localisation/localisation.h @@ -0,0 +1,39 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of OpenRCT2. + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#ifndef LOCALISATION_H +#define LOCALISATION_H + +#include "currency.h" +#include "format_codes.h" +#include "language.h" +#include "string_ids.h" + +void format_string(char *dest, rct_string_id format, void *args); +void generate_string_file(); +void reset_saved_strings(); +void error_string_quit(int error, rct_string_id format); +int get_string_length(char* buffer); + +// Real name data +extern const char real_name_initials[16]; +extern const char *real_names[1024]; + +#endif diff --git a/src/localisation/real_names.c b/src/localisation/real_names.c new file mode 100644 index 0000000000..0c1c8c1eef --- /dev/null +++ b/src/localisation/real_names.c @@ -0,0 +1,1052 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of OpenRCT2. + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#include "localisation.h" + +const char real_name_initials[] = { + 'B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'W' +}; + +const char *real_names[] = { + "Aaron", + "Abdul", + "Abraham", + "Abu", + "Adam", + "Adrian", + "Adriane", + "Aileen", + "Aisha", + "Akiko", + "Akira", + "Al", + "Ali", + "Alan", + "Alana", + "Albert", + "Alberta", + "Alec", + "Alesia", + "Alex", + "Alexa", + "Alexander", + "Alexandra", + "Alexis", + "Alf", + "Alfonso", + "Alfred", + "Alice", + "Alicia", + "Alison", + "Alistair", + "Allan", + "Allen", + "Allison", + "Allister", + "Alma", + "Alvin", + "Alyson", + "Amanda", + "Amber", + "Amilio", + "Amos", + "Amy", + "Ana", + "Anabel", + "Anastasia", + "Andie", + "Andrea", + "Andres", + "Andrew", + "Andy", + "Angel", + "Angela", + "Angelica", + "Angie", + "Angus", + "Anika", + "Ann", + "Anna", + "Anne", + "Annette", + "Annie", + "Annika", + "Anthony", + "Anton", + "Antonio", + "April", + "Archer", + "Archie", + "Arlene", + "Arnie", + "Arnold", + "Art", + "Arthur", + "Asaf", + "Ashley", + "Astrid", + "Aubrey", + "Austin", + "Austine", + "Avon", + "Avril", + "Axel", + "Aziz", + "Bailey", + "Barbara", + "Barney", + "Barry", + "Bart", + "Barton", + "Baxter", + "Beck", + "Becket", + "Becky", + "Belinda", + "Bella", + "Belle", + "Ben", + "Benjamin", + "Benny", + "Bernadette", + "Bernard", + "Bernice", + "Bess", + "Beth", + "Bethany", + "Bette", + "Betty", + "Bernard", + "Bernardette", + "Bernice", + "Berty", + "Bev", + "Beverly", + "Beverley", + "Bianca", + "Bill", + "Billie", + "Billy", + "Bjorn", + "Blaire", + "Blake", + "Blanche", + "Bo", + "Bob", + "Bobbie", + "Bobby", + "Bonnie", + "Boris", + "Brad", + "Bradley", + "Brady", + "Brandi", + "Brandon", + "Brandy", + "Brenda", + "Brendan", + "Brendon", + "Brent", + "Brett", + "Brian", + "Bridgit", + "Brigitte", + "Britney", + "Bruce", + "Bruno", + "Brutus", + "Bryan", + "Buck", + "Bucky", + "Bug", + "Burton", + "Byron", + "Cailin", + "Caitlyn", + "Cal", + "Caley", + "Callum", + "Calvin", + "Cameron", + "Camille", + "Campbell", + "Candy", + "Carl", + "Carla", + "Carlene", + "Carlos", + "Carmela", + "Carmen", + "Carol", + "Carole", + "Caroline", + "Carolyn", + "Carrie", + "Casey", + "Cassandra", + "Cassey", + "Cassie", + "Catherina", + "Catherine", + "Cathy", + "Caz", + "Cecelia", + "Cecil", + "Cecille", + "Ceilidh", + "Celeste", + "Chad", + "Charlene", + "Charles", + "Charlie", + "Charlotte", + "Chelsea", + "Cher", + "Cheri", + "Cheryll", + "Chip", + "Chloe", + "Chris", + "Christel", + "Christian", + "Christie", + "Christina", + "Christine", + "Christopher", + "Chuck", + "Cindy", + "Clark", + "Clair", + "Claire", + "Clara", + "Clarabell", + "Claude", + "Claudette", + "Claudia", + "Clayton", + "Cliff", + "Clifford", + "Clint", + "Clive", + "Clyde", + "Codey", + "Cody", + "Colin", + "Colleen", + "Connie", + "Coral", + "Corina", + "Craig", + "Curtis", + "Cynthia", + "Cyril", + "Darby", + "Daisy", + "Dale", + "Damien", + "Damon", + "Dan", + "Dana", + "Daniel", + "Danielle", + "Danni", + "Danny", + "Daphne", + "Darla", + "Darlene", + "Darrell", + "Darren", + "Darryl", + "Dave", + "David", + "Davie", + "Davis", + "Dawn", + "Dean", + "Debbie", + "Debby", + "Deborah", + "Debra", + "Debs", + "Deidre", + "Delores", + "Denise", + "Dennis", + "Denzel", + "Derek", + "Desmond", + "Diana", + "Diane", + "Dianna", + "Dick", + "Dillon", + "Dina", + "Dominic", + "Dominik", + "Don", + "Donald", + "Donna", + "Donovan", + "Doreen", + "Doris", + "Dorothy", + "Doug", + "Dougal", + "Douglas", + "Doyle", + "Drew", + "Duane", + "Dudley", + "Duncan", + "Dwight", + "Dylan", + "Earl", + "Ed", + "Eddie", + "Edgar", + "Edith", + "Edmond", + "Edward", + "Edwin", + "Edwina", + "Eileen", + "Elaine", + "Elina", + "Elisa", + "Elisabeth", + "Eliza", + "Elizabeth", + "Ella", + "Ellen", + "Elmer", + "Elsie", + "Emile", + "Emilio", + "Emily", + "Emma", + "Emmett", + "Enrique", + "Eric", + "Erica", + "Ericka", + "Erik", + "Erika", + "Erin", + "Erinn", + "Ernest", + "Esmeralda", + "Esta", + "Estella", + "Esther", + "Ethan", + "Eugene", + "Eva", + "Evan", + "Eve", + "Evelyn", + "Everett", + "Felix", + "Fabio", + "Falicia", + "Farah", + "Felicity", + "Fernando", + "Fergus", + "Fidelia", + "Finlay", + "Fiona", + "Fletcher", + "Flora", + "Florence", + "Floyd", + "Fly", + "Frances", + "Francesca", + "Francis", + "Francisco", + "Frank", + "Franklin", + "Franky", + "Fraser", + "Fred", + "Freda", + "Freddy", + "Fuzz", + "Gabriel", + "Gabriela", + "Gail", + "Garrett", + "Garth", + "Gary", + "Gavin", + "Gayle", + "Gene", + "Genevieve", + "Geoff", + "Geoffrey", + "George", + "Gerald", + "Geraldine", + "Gerard", + "Geri", + "Gerry", + "Gilbert", + "Gillian", + "Gina", + "Ginger", + "Giuseppe", + "Gladys", + "Glen", + "Glenda", + "Glenn", + "Gloria", + "Glyne", + "Goldie", + "Gordon", + "Grace", + "Graeme", + "Graham", + "Grant", + "Grayson", + "Greg", + "Gregor", + "Gregory", + "Gretchen", + "Gus", + "Guy", + "Gwen", + "Gwendoline", + "Hadrian", + "Hamish", + "Hank", + "Hannah", + "Hans", + "Harley", + "Harold", + "Harry", + "Harvey", + "Haseem", + "Hayley", + "Hazel", + "Heather", + "Hector", + "Heidi", + "Helen", + "Helena", + "Henri", + "Henry", + "Herbert", + "Herbie", + "Hermann", + "Hilda", + "Hollie", + "Holly", + "Homer", + "Horace", + "Howard", + "Hugh", + "Hugo", + "Iain", + "Ian", + "Imani", + "Imelda", + "Imran", + "Ingrid", + "Irene", + "Irma", + "Irving", + "Isaac", + "Isabella", + "Isabelle", + "Ishan", + "Isla", + "Ivan", + "Ivanna", + "Ivy", + "Izola", + "Jack", + "Jacque", + "Jacqueline", + "Jacqui", + "Jake", + "Jakob", + "James", + "Jacob", + "Jan", + "Janet", + "Jane", + "Janice", + "Jason", + "Jasper", + "Jay", + "Jayne", + "Jean", + "Jeanette", + "Jeff", + "Jeffrey", + "Jennifer", + "Jenny", + "Jeremy", + "Jerry", + "Jesse", + "Jessica", + "Jessie", + "Jessy", + "Jill", + "Jillian", + "Jim", + "Jimbo", + "Jimmy", + "Jo", + "Joan", + "Joann", + "Joanne", + "Jock", + "Jodi", + "Joe", + "Joel", + "Joelyn", + "Joey", + "Johan", + "John", + "Johnathan", + "Johnnie", + "Johnny", + "Jolynn", + "Jon", + "Jonah", + "Jonas", + "Jonathan", + "Joni", + "Jonny", + "Jordan", + "Jorge", + "Jose", + "Joseph", + "Josephine", + "Josh", + "Joshua", + "Joyce", + "Juan", + "Juana", + "Juanita", + "Judge", + "Judie", + "Judith", + "Judy", + "Julia", + "Julian", + "Julie", + "Juliette", + "Julio", + "Julius", + "June", + "Justin", + "Kaley", + "Kaitlyn", + "Kandice", + "Kara", + "Kareen", + "Karen", + "Karl", + "Karolyne", + "Karri", + "Kate", + "Katelyn", + "Katey", + "Kathy", + "Katherine", + "Kathie", + "Kathleen", + "Kathryn", + "Katie", + "Katrina", + "Katy", + "Katya", + "Kay", + "Keiko", + "Keith", + "Kelly", + "Kelsey", + "Ken", + "Kenneth", + "Kenny", + "Kerry", + "Kev", + "Kevin", + "Kieran", + "Kim", + "Kimberly", + "Kiriaki", + "Kirk", + "Klaus", + "Kris", + "Krista", + "Kristian", + "Kristy", + "Kurt", + "Kurtis", + "Kyle", + "Kylie", + "Laila", + "Lana", + "Lance", + "Larry", + "Lasse", + "Latisha", + "Laura", + "Lauren", + "Lauryn", + "Laurie", + "Lawrence", + "Leah", + "Lee", + "Leigh", + "Len", + "Lena", + "Lenore", + "Leo", + "Leon", + "Leonard", + "Leonardo", + "Leone", + "Leroy", + "Les", + "Leslie", + "Lesley", + "Lester", + "Lewis", + "Liam", + "Lillian", + "Lilly", + "Lily", + "Linda", + "Lindsay", + "Lindsey", + "Lisa", + "Lita", + "Logan", + "Lone", + "Loren", + "Loretta", + "Lori", + "Lorraine", + "Lottie", + "Louis", + "Louise", + "Lowell", + "Lucas", + "Lucy", + "Luis", + "Luke", + "Luther", + "Lydia", + "Lynn", + "Lynne", + "Lyssa", + "Mabel", + "Madeline", + "Maggie", + "Magnus", + "Mahamed", + "Malcolm", + "Mandy", + "Manuel", + "Marc", + "Marcela", + "Marci", + "Marcia", + "Marco", + "Marcus", + "Marcy", + "Margaret", + "Margarita", + "Maria", + "Mariah", + "Marian", + "Marianna", + "Marie", + "Marilyn", + "Marina", + "Marion", + "Marisa", + "Marissa", + "Marjorie", + "Mark", + "Markus", + "Marlene", + "Marlin", + "Marlon", + "Marshall", + "Martha", + "Martin", + "Martyn", + "Marvin", + "Mary", + "Mathew", + "Matt", + "Matthew", + "Maude", + "Maureen", + "Maurice", + "Mauricio", + "Mavis", + "Max", + "Maxine", + "May", + "Megan", + "Meghan", + "Mel", + "Melanie", + "Melany", + "Melinda", + "Melissa", + "Melody", + "Melvin", + "Mervin", + "Mhairi", + "Mia", + "Michael", + "Michelle", + "Mick", + "Mickey", + "Miguel", + "Mikael", + "Mike", + "Mikey", + "Miki", + "Mikko", + "Mildred", + "Millie", + "Milly", + "Milton", + "Miranda", + "Miriam", + "Mirriam", + "Mitchell", + "Mo", + "Molly", + "Monica", + "Monique", + "Monty", + "Morgan", + "Morten", + "Moses", + "Morris", + "Muriel", + "Murphy", + "Murray", + "Mustafa", + "Myles", + "Myrissa", + "Myrtle", + "Nadine", + "Nancy", + "Nanette", + "Naomi", + "Natalia", + "Natalie", + "Natasha", + "Nathan", + "Nathaniel", + "Neil", + "Nellie", + "Nelly", + "Nelson", + "Neville", + "Nicholas", + "Nichole", + "Nick", + "Nico", + "Nicola", + "Nicolas", + "Nicole", + "Nigel", + "Nikia", + "Nikki", + "Nina", + "Noah", + "Noel", + "Norma", + "Norman", + "Norris", + "Norvall", + "Olga", + "Olive", + "Oliver", + "Ollie", + "Omar", + "Oona", + "Orve", + "Orville", + "Oscar", + "Otto", + "Owen", + "Paisley", + "Pam", + "Pamela", + "Pandora", + "Pat", + "Patricia", + "Patrick", + "Patty", + "Paul", + "Paula", + "Pauline", + "Pedro", + "Peggy", + "Penelope", + "Penny", + "Perry", + "Pete", + "Peter", + "Phil", + "Philip", + "Phillip", + "Phyllis", + "Polly", + "Preston", + "Qasim", + "Quentin", + "Quinn", + "Rachel", + "Rae", + "Rafael", + "Raj", + "Raja", + "Ralph", + "Ramon", + "Randal", + "Rashid", + "Raquel", + "Raul", + "Ray", + "Raymond", + "Raymondo", + "Rebecca", + "Reg", + "Regina", + "Reginald", + "Reinhold", + "Rene", + "Reuben", + "Rex", + "Rhonda", + "Richard", + "Rick", + "Ricky", + "Rita", + "Robb", + "Robert", + "Roberta", + "Robin", + "Robina", + "Robyn", + "Robynne", + "Rock", + "Rockie", + "Rod", + "Rodney", + "Rodrigo", + "Roland", + "Rolf", + "Romeo", + "Ronald", + "Ronan", + "Ronnie", + "Roger", + "Rosalind", + "Rosanna", + "Rosanned", + "Rose", + "Rosemary", + "Rosetta", + "Rosie", + "Ross", + "Roxanne", + "Roy", + "Russell", + "Rosty", + "Ruben", + "Ruby", + "Ruth", + "Ryan", + "Sabrina", + "Sadie", + "Sally", + "Sam", + "Samantha", + "Sammy", + "Samuel", + "Sandra", + "Sandy", + "Sara", + "Sarah", + "Sasha", + "Saul", + "Scot", + "Scott", + "Sean", + "Sebastian", + "Sergio", + "Shakira", + "Shannon", + "Shari", + "Sharnell", + "Sharon", + "Sharyn", + "Shawn", + "Shelby", + "Shelley", + "Sherene", + "Sheri", + "Sherman", + "Sherry", + "Shirley", + "Sheryl", + "Shivani", + "Shona", + "Sian", + "Sid", + "Sidney", + "Simon", + "Sindy", + "Sinead", + "Sofia", + "Sonny", + "Sonja", + "Sonya", + "Sophia", + "Sophie", + "Spencer", + "Stacey", + "Stan", + "Stanley", + "Stefan", + "Stephen", + "Stephanie", + "Steve", + "Steven", + "Stewart", + "Stuart", + "Sue", + "Suki", + "Susan", + "Susana", + "Susanne", + "Susie", + "Suzanne", + "Sven", + "Sylvester", + "Sylvia", + "Tabatha", + "Tamara", + "Tammie", + "Tamsin", + "Tania", + "Tanya", + "Tara", + "Taylor", + "Ted", + "Teresa", + "Terrance", + "Terry", + "Tess", + "Tessa", + "Tex", + "Thelma", + "Theodore", + "Theresa", + "Thomas", + "Tiffany", + "Tiger", + "Tiko", + "Tillie", + "Tim", + "Timmy", + "Timothy", + "Tina", + "Toby", + "Todd", + "Tom", + "Tomaki", + "Tommy", + "Tonia", + "Tonie", + "Tony", + "Tracy", + "Travis", + "Trevor", + "Tricia", + "Trixie", + "Troy", + "Tucker", + "Tyler", + "Tyson", + "Ulysses", + "Uri", + "Val", + "Valerie", + "Vanessa", + "Vani", + "Vaughn", + "Velma", + "Vernon", + "Veronica", + "Vicki", + "Vicky", + "Victor", + "Victoria", + "Vijay", + "Vince", + "Vincent", + "Vinnie", + "Virginia", + "Viv", + "Vivian", + "Viviene", + "Wally", + "Walt", + "Walter", + "Walton", + "Wanda", + "Warren", + "Wayne", + "Wendell", + "Wendy", + "Wes", + "Wesley", + "Whitney", + "Will", + "William", + "Willie", + "Willis", + "Wilson", + "Winston", + "Wyatt", + "Xavier", + "Yasmin", + "Yogi", + "Ysabel", + "Yvonne", + "Zachary", + "Zachery", + "Zola" +}; \ No newline at end of file diff --git a/src/string_ids.h b/src/localisation/string_ids.h similarity index 64% rename from src/string_ids.h rename to src/localisation/string_ids.h index 91d2b031f9..ec9639b635 100644 --- a/src/string_ids.h +++ b/src/localisation/string_ids.h @@ -21,116 +21,6 @@ #ifndef _STRING_IDS_H_ #define _STRING_IDS_H_ -typedef unsigned short rct_string_id; - -void format_string(char *dest, rct_string_id format, void *args); -void generate_string_file(); -void reset_saved_strings(); -void error_string_quit(int error, rct_string_id format); - -char format_get_code(const char *token); -const char *format_get_token(char code); - -enum { - // Font format codes - - // The next byte specifies the X coordinate - FORMAT_MOVE_X = 1, - // The next byte specifies the palette - FORMAT_ADJUST_PALETTE, - - // Moves to the next line - FORMAT_NEWLINE = 5, - // Moves less than NEWLINE - FORMAT_NEWLINE_SMALLER, - - FORMAT_TINYFONT, - FORMAT_BIGFONT, - FORMAT_MEDIUMFONT, - FORMAT_SMALLFONT, - - FORMAT_OUTLINE, - FORMAT_OUTLINE_OFF, - - // Changes the colour of the text to a predefined window colour. - FORMAT_WINDOW_COLOUR_1, - FORMAT_WINDOW_COLOUR_2, - FORMAT_WINDOW_COLOUR_3, - - // The next 2 bytes specify the X and Y coordinates - FORMAT_NEWLINE_X_Y = 17, - - // The next 4 bytes specify the sprite - FORMAT_INLINE_SPRITE = 23, - - // Non ascii-characters - FORMAT_ENDQUOTES = 34, - - // Argument format codes - FORMAT_ARGUMENT_CODE_START = 123, - FORMAT_COMMA32 = 123, - FORMAT_INT32, - FORMAT_COMMA2DP32, - FORMAT_COMMA16, - FORMAT_UINT16, - FORMAT_CURRENCY2DP, - FORMAT_CURRENCY, - FORMAT_STRINGID, - FORMAT_STRINGID2, - FORMAT_STRING, - FORMAT_MONTHYEAR, - FORMAT_MONTH, - FORMAT_VELOCITY, - FORMAT_POP16, - FORMAT_PUSH16, - FORMAT_DURATION, - FORMAT_REALTIME, - FORMAT_LENGTH, - FORMAT_SPRITE, - - // Colour format codes - FORMAT_COLOUR_CODE_START = 142, - FORMAT_BLACK = 142, - FORMAT_GREY, - FORMAT_WHITE, - FORMAT_RED, - FORMAT_GREEN, - FORMAT_YELLOW, - FORMAT_TOPAZ, - FORMAT_CELADON, - FORMAT_BABYBLUE, - FORMAT_PALELAVENDER, - FORMAT_PALEGOLD, - FORMAT_LIGHTPINK, - FORMAT_PEARLAQUA, - FORMAT_PALESILVER, - FORMAT_COLOUR_CODE_END = FORMAT_PALESILVER, - - // Extra non-ascii characters - FORMAT_AMINUSCULE = 159, - FORMAT_UP, - FORMAT_POUND = 163, - FORMAT_YEN = 165, - FORMAT_COPYRIGHT = 169, - FORMAT_DOWN, - FORMAT_LEFTGUILLEMET, - FORMAT_TICK, - FORMAT_CROSS, - FORMAT_RIGHT = 175, - FORMAT_DEGREE, - FORMAT_SQUARED = 178, - FORMAT_OPENQUOTES = 180, - FORMAT_EURO = 181, - FORMAT_APPROX = 184, - FORMAT_POWERNEGATIVEONE, - FORMAT_BULLET, - FORMAT_RIGHTGUILLEMET, - FORMAT_SMALLUP, - FORMAT_SMALLDOWN, - FORMAT_LEFT, - FORMAT_INVERTEDQUESTION -}; - enum { STR_NONE = -1, @@ -251,6 +141,20 @@ enum { STR_LOWER_COST_AMOUNT = 985, STR_COST_AMOUNT = 986, + STR_CONSTRUCTION = 990, + + STR_DEMOLISH_RIDE_TIP = 992, + + STR_OVERALL_VIEW = 996, + STR_VIEW_SELECTION = 997, + + STR_CANT_OPEN = 1002, + STR_CANT_TEST = 1003, + STR_CANT_CLOSE = 1004, + STR_CANT_START_CONSTRUCTION_ON = 1005, + STR_MUST_BE_CLOSED_FIRST = 1006, + STR_UNABLE_TO_CREATE_ENOUGH_VEHICLES = 1007, + STR_OPEN_CLOSE_OR_TEST_RIDE = 1008, STR_OPEN_OR_CLOSE_ALL_RIDES = 1009, STR_OPEN_OR_CLOSE_PARK_TIP = 1010, STR_CLOSE_ALL = 1011, @@ -258,6 +162,8 @@ enum { STR_CLOSE_PARK = 1013, STR_OPEN_PARK = 1014, + STR_CANT_CHANGE_OPERATING_MODE = 1017, + STR_LOCATE_SUBJECT_TIP = 1027, STR_LOAD_GAME_DIALOG_TITLE = 1036, @@ -267,6 +173,99 @@ enum { STR_RCT2_LANDSCAPE_FILE = 1045, STR_RIDES_IN_PARK_TIP = 1053, + STR_NAME_RIDE_TIP = 1054, + + STR_RIDE_ATTRACTION_NAME = 1057, + STR_ENTER_NEW_NAME_FOR_THIS_RIDE_ATTRACTION = 1058, + STR_CANT_RENAME_RIDE_ATTRACTION = 1059, + STR_INVALID_RIDE_ATTRACTION_NAME = 1060, + + STR_RIDE_MODE_START = 1061, + STR_RIDE_MODE_NORMAL = STR_RIDE_MODE_START + 0, + STR_RIDE_MODE_CONTINUOUS_CIRCUIT = STR_RIDE_MODE_START + 1, + STR_RIDE_MODE_REVERSE_INCLINE_LAUNCHED_SHUTTLE = STR_RIDE_MODE_START + 2, + STR_RIDE_MODE_POWERED_LAUNCH = STR_RIDE_MODE_START + 3, + STR_RIDE_MODE_SHUTTLE = STR_RIDE_MODE_START + 4, + STR_RIDE_MODE_BOAT_HIRE = STR_RIDE_MODE_START + 5, + STR_RIDE_MODE_UPWARD_LAUNCH = STR_RIDE_MODE_START + 6, + STR_RIDE_MODE_ROTATING_LIFT = STR_RIDE_MODE_START + 7, + STR_RIDE_MODE_STATION_TO_STATION = STR_RIDE_MODE_START + 8, + STR_RIDE_MODE_SINGLE_RIDE_PER_ADMISSION = STR_RIDE_MODE_START + 9, + STR_RIDE_MODE_UNLIMITED_RIDES_PER_ADMISSION = STR_RIDE_MODE_START + 10, + STR_RIDE_MODE_MAZE = STR_RIDE_MODE_START + 11, + STR_RIDE_MODE_RACE = STR_RIDE_MODE_START + 12, + STR_RIDE_MODE_BUMPER_CAR = STR_RIDE_MODE_START + 13, + STR_RIDE_MODE_SWING = STR_RIDE_MODE_START + 14, + STR_RIDE_MODE_SHOP_STALL = STR_RIDE_MODE_START + 15, + STR_RIDE_MODE_ROTATION = STR_RIDE_MODE_START + 16, + STR_RIDE_MODE_FORWARD_ROTATION = STR_RIDE_MODE_START + 17, + STR_RIDE_MODE_BACKWARD_ROTATION = STR_RIDE_MODE_START + 18, + STR_RIDE_MODE_FILM_AVENGING_AVIATORS = STR_RIDE_MODE_START + 19, + STR_RIDE_MODE_3D_FILM_MOUSE_TAILS = STR_RIDE_MODE_START + 20, + STR_RIDE_MODE_SPACE_RINGS = STR_RIDE_MODE_START + 21, + STR_RIDE_MODE_BEGINNERS = STR_RIDE_MODE_START + 22, + STR_RIDE_MODE_LIM_POWERED_LAUNCH = STR_RIDE_MODE_START + 23, + STR_RIDE_MODE_FILM_THRILL_RIDERS = STR_RIDE_MODE_START + 24, + STR_RIDE_MODE_3D_FILM_STORM_CHASERS = STR_RIDE_MODE_START + 25, + STR_RIDE_MODE_3D_FILM_SPACE_RAIDERS = STR_RIDE_MODE_START + 26, + STR_RIDE_MODE_INTENSE = STR_RIDE_MODE_START + 27, + STR_RIDE_MODE_BERSERK = STR_RIDE_MODE_START + 28, + STR_RIDE_MODE_HAUNTED_HOUSE = STR_RIDE_MODE_START + 29, + STR_RIDE_MODE_CIRCUS_SHOW = STR_RIDE_MODE_START + 30, + STR_RIDE_MODE_DOWNWARD_LAUNCH = STR_RIDE_MODE_START + 31, + STR_RIDE_MODE_CROOKED_HOUSE = STR_RIDE_MODE_START + 32, + STR_RIDE_MODE_FREEFALL_DROP = STR_RIDE_MODE_START + 33, + STR_RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED = STR_RIDE_MODE_START + 34, + STR_RIDE_MODE_POWERED_LAUNCH_35 = STR_RIDE_MODE_START + 35, + STR_RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED_MODE = STR_RIDE_MODE_START + 36, + + STR_MOVING_TO_END_OF = 1098, + STR_WAITING_FOR_PASSENGERS_AT = 1099, + STR_WAITING_TO_DEPART = 1100, + STR_DEPARTING = 1101, + STR_TRAVELLING_AT_0 = 1102, + STR_ARRIVING_AT = 1103, + STR_UNLOADING_PASSENGERS_AT = 1104, + STR_TRAVELLING_AT_1 = 1105, + STR_CRASHING = 1106, + STR_CRASHED_0 = 1107, + STR_TRAVELLING_AT_2 = 1108, + STR_SWINGING = 1109, + STR_ROTATING_0 = 1110, + STR_ROTATING_1 = 1111, + STR_OPERATING_0 = 1112, + STR_SHOWING_FILM = 1113, + STR_ROTATING_2 = 1114, + STR_OPERATING_1 = 1115, + STR_OPERATING_2 = 1116, + STR_DOING_CIRCUS_SHOW = 1117, + STR_OPERATING_3 = 1118, + STR_WAITING_FOR_CABLE_LIFT = 1119, + STR_TRAVELLING_AT_3 = 1120, + STR_STOPPING_0 = 1121, + STR_WAITING_FOR_PASSENGERS = 1122, + STR_WAITING_TO_START = 1123, + STR_STARTING = 1124, + STR_OPERATING = 1125, + STR_STOPPING_1 = 1126, + STR_UNLOADING_PASSENGERS = 1127, + STR_STOPPED_BY_BLOCK_BRAKES = 1128, + STR_ALL_VEHICLES_IN_SAME_COLOURS = 1129, + STR_DIFFERENT_COLOURS_PER = 1130, + STR_DIFFERENT_COLOURS_PER_VEHICLE = 1131, + + STR_SELECT_MAIN_COLOUR_TIP = 1136, + STR_SELECT_ADDITIONAL_COLOUR_1_TIP = 1137, + STR_SELECT_ADDITIONAL_COLOUR_2_TIP = 1138, + STR_SELECT_SUPPORT_STRUCTURE_COLOUR_TIP = 1139, + STR_SELECT_VEHICLE_COLOUR_SCHEME_TIP = 1140, + STR_SELECT_VEHICLE_TO_MODIFY_TIP = 1141, + + STR_QUARTER_LOAD = 1148, + STR_HALF_LOAD = 1149, + STR_THREE_QUARTER_LOAD = 1150, + STR_FULL_LOAD = 1151, + STR_ANY_LOAD = 1152, STR_PLACE_SCENERY_TIP = 1159, STR_ADJUST_WATER_TIP = 1160, @@ -288,9 +287,9 @@ enum { STR_SLOPE_UP_TIP = 1188, STR_CONSTRUCT_THE_SELECTED_FOOTPATH_SECTION_TIP = 1189, STR_REMOVE_PREVIOUS_FOOTPATH_SECTION_TIP = 1190, - STR_COST = 1191, + STR_BLACK_STRING = 1191, STR_LOSS = 1192, - + STR_WINDOW_COLOUR_2_STRING = 1193, STR_CLOSED = 1194, STR_TEST_RUN = 1195, STR_OPEN = 1196, @@ -304,10 +303,24 @@ enum { STR_QUEUE_PEOPLE = 1203, STR_QUEUE_TIME_LABEL = 1204, STR_QUEUE_TIME_PLURAL_LABEL = 1205, + STR_WAIT_FOR = 1206, + + STR_LEAVE_IF_ANOTHER_TRAIN_ARRIVES = 1207, + STR_LEAVE_IF_ANOTHER_BOAT_ARRIVES = 1208, + STR_WAIT_FOR_PASSENGERS_BEFORE_DEPARTING_TIP = 1209, + STR_LEAVE_IF_ANOTHER_VEHICLE_ARRIVES_TIP = 1210, + STR_MINIMUM_WAITING_TIME = 1211, + STR_MAXIMUM_WAITING_TIME = 1212, + STR_MINIMUM_LENGTH_BEFORE_DEPARTING_TIP = 1213, + STR_MAXIMUM_LENGTH_BEFORE_DEPARTING_TIP = 1214, + STR_SYNCHRONISE_WITH_ADJACENT_STATIONS = 1215, + STR_SYNCHRONISE_WITH_ADJACENT_STATIONS_TIP = 1216, STR_NUMERIC_UP = 1218, STR_NUMERIC_DOWN = 1219, - + STR_EXIT_ONLY = 1220, + STR_NO_ENTRANCE = 1221, + STR_NO_EXIT = 1222, STR_TRANSPORT_RIDES_TIP = 1223, STR_GENTLE_RIDES_TIP = 1224, STR_ROLLER_COASTERS_TIP = 1225, @@ -316,13 +329,53 @@ enum { STR_SHOPS_STALLS_TIP = 1228, STR_ROTATE_OBJECTS_90 = 1327, + STR_LAUNCH_SPEED = 1329, + STR_LAUNCH_SPEED_TIP = 1330, + + STR_NO_TEST_RESULTS_YET = 1339, + STR_MAX_SPEED = 1340, + STR_RIDE_TIME = 1341, + STR_RIDE_LENGTH = 1344, + STR_AVERAGE_SPEED = 1347, + STR_MAX_POSITIVE_VERTICAL_G = 1348, + STR_MAX_POSITIVE_VERTICAL_G_RED = 1349, + STR_MAX_NEGATIVE_VERTICAL_G = 1350, + STR_MAX_NEGATIVE_VERTICAL_G_RED = 1351, + STR_MAX_LATERAL_G = 1352, + STR_MAX_LATERAL_G_RED = 1353, + STR_HIGHEST_DROP_HEIGHT = 1354, + STR_DROPS = 1355, + STR_INVERSIONS = 1356, + STR_HOLES = 1357, + STR_TOTAL_AIR_TIME = 1358, + STR_QUEUE_TIME_MINUTE = 1359, + STR_QUEUE_TIME_MINUTES = 1360, + + STR_VIEW_OF_RIDE_ATTRACTION_TIP = 1392, + STR_VEHICLE_DETAILS_AND_OPTIONS_TIP = 1393, + STR_OPERATING_OPTIONS_TIP = 1394, + STR_MAINTENANCE_OPTIONS_TIP = 1395, + STR_COLOUR_SCHEME_OPTIONS_TIP = 1396, + STR_SOUND_AND_MUSIC_OPTIONS_TIP = 1397, + STR_MEASUREMENTS_AND_TEST_DATA_TIP = 1398, + STR_GRAPHS_TIP = 1399, + + STR_ROTATE_90_TIP = 1404, + STR_MIRROR_IMAGE_TIP = 1405, + STR_TOGGLE_SCENERY_TIP = 1406, STR_BUILD_THIS = 1407, STR_COST_LABEL = 1408, + STR_DATA_LOGGING_NOT_AVAILABLE_FOR_THIS_TYPE_OF_RIDE = 1412, + STR_DATA_LOGGING_WILL_START_WHEN_NEXT_LEAVES = 1413, + STR_LOGGING_DATA_FROM_TIP = 1422, STR_QUEUE_LINE_PATH_TIP = 1423, STR_FOOTPATH_TIP = 1424, + STR_CUSTOMERS_PER_HOUR = 1427, + STR_RIDE_INCOME_ADMISSION_PRICE = 1428, + STR_FREE = 1430, STR_WALKING = 1431, STR_HEADING_FOR = 1432, @@ -346,15 +399,37 @@ enum { STR_GUESTS = 1463, STR_STAFF = 1468, + + STR_SPEED = 1471, + STR_SPEED_TIP = 1472, + STR_EXCITEMENT_RATING = 1473, + STR_EXCITEMENT_RATING_NOT_YET_AVAILABLE = 1474, + STR_INTENSITY_RATING = 1475, + STR_INTENSITY_RATING_NOT_YET_AVAILABLE = 1476, + STR_INTENSITY_RATING_RED = 1477, + STR_NAUSEA_RATING = 1478, + STR_NAUSEA_RATING_NOT_YET_AVAILABLE = 1479, + STR_THOUGHT_START = 1480, STR_CONSTRUCT_FOOTPATH_ON_LAND_TIP = 1655, STR_CONSTRUCT_BRIDGE_OR_TUNNEL_FOOTPATH_TIP = 1656, + STR_SATISFACTION_UNKNOWN = 1668, + STR_SATISFACTION_PERCENT = 1669, + STR_TOTAL_CUSTOMERS = 1670, + STR_TOTAL_PROFIT = 1671, + + STR_POPULARITY_UNKNOWN = 1677, + STR_POPULARITY_PERCENT = 1678, + STR_GUESTS_TIP = 1693, STR_STAFF_TIP = 1694, + STR_INCOME_AND_COSTS_TIP = 1695, + STR_CUSTOMER_INFORMATION_TIP = 1696, + STR_TOO_MANY_PEOPLE_IN_GAME = 1699, STR_HIRE_HANDYMAN = 1700, STR_HIRE_MECHANIC = 1701, @@ -375,12 +450,25 @@ enum { STR_CANT_OPEN_PARK = 1723, STR_CANT_CLOSE_PARK = 1724, + STR_NUMBER_OF_LAPS = 1734, + STR_NUMBER_OF_LAPS_TIP = 1735, + STR_RACE_WON_BY_GUEST = 1739, STR_RACE_WON_BY = 1740, + STR_MAX_PEOPLE_ON_RIDE = 1742, + STR_MAX_PEOPLE_ON_RIDE_TIP = 1743, + + STR_TIME_LIMIT = 1747, + STR_TIME_LIMIT_TIP = 1748, + STR_INDIVIDUAL_GUESTS_TIP = 1752, STR_SUMMARISED_GUESTS_TIP = 1753, STR_ADMISSION_PRICE = 1756, + STR_RELIABILITY_LABEL_1757 = 1757, + + STR_NUMBER_OF_SWINGS = 1769, + STR_NUMBER_OF_SWINGS_TIP = 1770, STR_OFF = 1775, STR_ON = 1776, @@ -393,6 +481,18 @@ enum { STR_FIXING_RIDE = 1794, STR_ANSWERING_RADIO_CALL = 1795, + STR_SAFETY_CUT_OUT = 1800, + STR_RESTRAINTS_STUCK_CLOSED = 1801, + STR_RESTRAINTS_STUCK_OPEN = 1802, + STR_DOORS_STUCK_CLOSED = 1803, + STR_DOORS_STUCK_OPEN = 1804, + STR_VEHICLE_MALFUNCTION = 1805, + STR_BRAKES_FAILURE = 1806, + STR_CONTROL_FAILURE = 1807, + + STR_LAST_BREAKDOWN = 1808, + STR_CURRENT_BREAKDOWN = 1809, + STR_ACTIONS = 1814, STR_THOUGHTS = STR_ACTIONS + 1, STR_INFORMATION_TYPE_TIP = 1816, @@ -403,6 +503,10 @@ enum { STR_GUESTS_FILTER_THINKING = STR_GUESTS_FILTER + 1, STR_GUESTS_FILTER_THINKING_ABOUT = STR_GUESTS_FILTER + 2, + STR_SHOW_GUESTS_THOUGHTS_ABOUT_THIS_RIDE_ATTRACTION_TIP = 1823, + STR_SHOW_GUESTS_ON_THIS_RIDE_ATTRACTION_TIP = 1824, + STR_SHOW_GUESTS_QUEUING_FOR_THIS_RIDE_ATTRACTION_TIP = 1825, + STR_STATUS = 1826, STR_POPULARITY = 1827, STR_SATISFACTION = 1828, @@ -424,6 +528,18 @@ enum { STR_RIDE_LIST_INFORMATION_TYPE_TIP = 1844, STR_NUM_GUESTS = 1846, + STR_PLAY_MUSIC = 1849, + STR_SELECT_MUSIC_TIP = 1850, + STR_RUNNING_COST_PER_HOUR = 1851, + STR_RUNNING_COST_UNKNOWN = 1852, + STR_BUILT_THIS_YEAR = 1853, + STR_BUILT_LAST_YEAR = 1854, + STR_BUILT_YEARS_AGO = 1855, + + STR_PROFIT_PER_ITEM_SOLD = 1856, + STR_LOSS_PER_ITEM_SOLD = 1857, + STR_COST_PER_MONTH = 1858, + STR_HANDYMAN_PLURAL = 1859, STR_MECHANIC_PLURAL = 1860, STR_SECURITY_GUARD_PLURAL = 1861, @@ -434,8 +550,32 @@ enum { STR_ENTERTAINER_SINGULAR = 1866, STR_STAFF_LIST_COUNTER = 1867, + STR_NUMBER_OF_ROTATIONS = 1869, + STR_NUMBER_OF_ROTATIONS_TIP = 1870, + + STR_INCOME_PER_HOUR = 1873, + STR_PROFIT_PER_HOUR = 1874, + + STR_INSPECT_RIDES = 1876, + STR_FIX_RIDES = 1877, + STR_INSPECTION = 1878, + + STR_EVERY_10_MINUTES = 1879, + STR_EVERY_20_MINUTES = 1880, + STR_EVERY_30_MINUTES = 1881, + STR_EVERY_45_MINUTES = 1882, + STR_EVERY_HOUR = 1883, + STR_EVERY_2_HOURS = 1884, + STR_NEVER = 1885, + STR_INSPECTING_RIDE = 1886, + STR_TIME_SINCE_LAST_INSPECTION_MINUTES = 1887, + STR_TIME_SINCE_LAST_INSPECTION_MORE_THAN_4_HOURS = 1888, + STR_DOWN_TIME_LABEL_1889 = 1889, + STR_SELECT_HOW_OFTEN_A_MECHANIC_SHOULD_CHECK_THIS_RIDE = 1890, + + STR_ITEMS_SOLD = 1894, STR_BUILD_RIDE_TIP = 1895, STR_FINANCES_SUMMARY_EXPENDITURE_INCOME = 1896, STR_FINANCES_SUMMARY_RIDE_CONSTRUCTION = 1897, @@ -480,6 +620,16 @@ enum { STR_MARKETING = 1953, STR_RESEARCH_FUNDING = 1954, + STR_NUMBER_OF_CIRCUITS = 1955, + STR_NUMBER_OF_CIRCUITS_TIP = 1956, + + STR_ON_RIDE_PHOTO_PRICE = 1963, + + STR_MAIN_COLOUR_SCHEME = 2971, + STR_ALTERNATIVE_COLOUR_SCHEME_1 = 2972, + STR_ALTERNATIVE_COLOUR_SCHEME_2 = 2973, + STR_ALTERNATIVE_COLOUR_SCHEME_3 = 2974, + STR_ITEM_START = 1988, STR_ITEM_SINGULAR_START = 2044, STR_ITEM2_START = 2090, @@ -566,6 +716,17 @@ enum { STR_CHANGE_BASE_LAND_TIP = 2294, STR_CHANGE_VERTICAL_LAND_TIP = 2295, + STR_SELECT_DESIGN = 2307, + STR_TRACK_DESIGNS = 2308, + STR_BUILD_CUSTOM_DESIGN = 2310, + + STR_TRACK_LIST_EXCITEMENT_RATING = 2311, + STR_TRACK_LIST_INTENSITY_RATING = 2312, + STR_TRACK_LIST_NAUSEA_RATING = 2313, + STR_TRACK_LIST_RIDE_LENGTH = 2314, + STR_TRACK_LIST_COST_AROUND = 2315, + STR_TRACK_LIST_SPACE_REQUIRED = 2316, + STR_SOUND_QUALITY = 2317, STR_SOUND_LOW = 2318, STR_SOUND_MEDIUM = 2319, @@ -608,12 +769,12 @@ enum { STR_LOW = 2369, STR_AVERAGE = 2370, STR_HIGH = 2371, - //STR_LOW = 2372, - STR_MEDIUM = 2373, - //STR_HIGH = 2374, - STR_VERY_HIGH = 2375, - STR_EXTREME = 2376, - STR_ULTRA_EXTREME = 2377, + STR_RATING_LOW = 2372, + STR_RATING_MEDIUM = 2373, + STR_RATING_HIGH = 2374, + STR_RATING_VERY_HIGH = 2375, + STR_RATING_EXTREME = 2376, + STR_RATING_ULTRA_EXTREME = 2377, STR_ADJUST_SMALLER_LAND_TIP = 2378, STR_ADJUST_LARGER_LAND_TIP = 2379, @@ -708,6 +869,13 @@ enum { STR_RESEARCH_NEW_SHOPS_AND_STALLS = 2475, STR_RESEARCH_NEW_SCENERY_AND_THEMING = 2476, + STR_SELECT_OPERATING_MODE = 2477, + + STR_SHOW_GRAPH_OF_VELOCITY_AGAINST_TIME_TIP = 2478, + STR_SHOW_GRAPH_OF_ALTITUDE_AGAINST_TIME_TIP = 2479, + STR_SHOW_GRAPH_OF_VERTICAL_ACCELERATION_AGAINST_TIME_TIP = 2480, + STR_SHOW_GRAPH_OF_LATERAL_ACCELERATION_AGAINST_TIME_TIP = 2481, + STR_PROFIT_PER_WEEK_AND_PARK_VALUE_TIP = 2482, STR_FINANCES_WEEKLY_PROFIT_POSITIVE = 2483, STR_FINANCES_WEEKLY_PROFIT_LOSS = 2484, @@ -718,6 +886,15 @@ enum { STR_REAL_NAME_TIP = 2488, STR_HOTKEY = 2489, + STR_SHORTCUT_DESCRIPTION_0 = 2493, + + STR_SHORTCUT_DESCRIPTION_31 = 2524, + STR_INDIVIDUAL_KEYS_BASE = 2525, + + STR_SHORTCUT_ENTRY_FORMAT = 2781, + STR_SHIFT_PLUS = 2782, + STR_CTRL_PLUS = 2783, + STR_FINACNES_PARK_VALUE = 2787, STR_ENTER_NAME_INTO_SCENARIO_CHART = 2790, @@ -807,19 +984,83 @@ enum { STR_LICENCE_AGREEMENT_NOTICE_1 = 2969, STR_LICENCE_AGREEMENT_NOTICE_2 = 2970, + STR_COLOUR_SCHEME_TO_CHANGE_TIP = 2975, + STR_PAINT_INDIVIDUAL_AREA_TIP = 2976, + STR_UNABLE_TO_LOAD_FILE = 3010, STR_FILE_CONTAINS_INVALID_DATA = 3011, + STR_MUSIC_STYLE_START = 3012, + STR_DODGEMS_BEAT_STYLE = STR_MUSIC_STYLE_START + 0, + STR_FAIRGROUND_ORGAN_STYLE = STR_MUSIC_STYLE_START + 1, + STR_ROMAN_FANFARE_STYLE = STR_MUSIC_STYLE_START + 2, + STR_ORIENTAL_STYLE = STR_MUSIC_STYLE_START + 3, + STR_MARTIAN_STYLE = STR_MUSIC_STYLE_START + 4, + STR_JUNGLE_DRUMS_STYLE = STR_MUSIC_STYLE_START + 5, + STR_EGYPTIAN_STYLE = STR_MUSIC_STYLE_START + 6, + STR_TOYLAND_STYLE = STR_MUSIC_STYLE_START + 7, + // STR_??? = STR_MUSIC_STYLE_START + 8, + STR_SPACE_STYLE = STR_MUSIC_STYLE_START + 9, + STR_HORROR_STYLE = STR_MUSIC_STYLE_START + 10, + STR_TECHNO_STYLE = STR_MUSIC_STYLE_START + 11, + STR_GENTLE_STYLE = STR_MUSIC_STYLE_START + 12, + STR_SUMMER_STYLE = STR_MUSIC_STYLE_START + 13, + STR_WATER_STYLE = STR_MUSIC_STYLE_START + 14, + STR_WILD_WEST_STYLE = STR_MUSIC_STYLE_START + 15, + STR_JURASSIC_STYLE = STR_MUSIC_STYLE_START + 16, + STR_ROCK_STYLE = STR_MUSIC_STYLE_START + 17, + STR_RAGTIME_STYLE = STR_MUSIC_STYLE_START + 18, + STR_FANTASY_STYLE = STR_MUSIC_STYLE_START + 19, + STR_ROCK_STYLE_2 = STR_MUSIC_STYLE_START + 20, + STR_ICE_STYLE = STR_MUSIC_STYLE_START + 21, + STR_SNOW_STYLE = STR_MUSIC_STYLE_START + 22, + STR_CUSTOM_MUSIC_1 = STR_MUSIC_STYLE_START + 23, + STR_CUSTOM_MUSIC_2 = STR_MUSIC_STYLE_START + 24, + STR_MEDIEVAL_STYLE = STR_MUSIC_STYLE_START + 25, + STR_URBAN_STYLE = STR_MUSIC_STYLE_START + 26, + STR_ORGAN_STYLE = STR_MUSIC_STYLE_START + 27, + STR_MECHANICAL_STYLE = STR_MUSIC_STYLE_START + 28, + STR_MODERN_STYLE = STR_MUSIC_STYLE_START + 29, + STR_PIRATES_STYLE = STR_MUSIC_STYLE_START + 30, + STR_ROCK_STYLE_3 = STR_MUSIC_STYLE_START + 31, + STR_CANDY_STYLE = STR_MUSIC_STYLE_START + 32, + + STR_SELECT_MUSIC_STYLE_TIP = 3045, + STR_WHITE = 3055, STR_TRANSLUCENT = 3056, STR_CONSTRUCTION_MARKER = 3057, + STR_BRICK_WALLS = 3058, + STR_HEDGES = 3059, + STR_ICE_BLOCKS = 3060, + STR_WOODEN_FENCES = 3061, + STR_BEGINNER_PARKS = 3064, STR_CHALLENGING_PARKS = STR_BEGINNER_PARKS + 1, STR_EXPERT_PARKS = STR_BEGINNER_PARKS + 2, STR_REAL_PARKS = STR_BEGINNER_PARKS + 3, STR_OTHER_PARKS = STR_BEGINNER_PARKS + 4, + STR_SAME_PRICE_THROUGHOUT_PARK = 3071, + STR_SAME_PRICE_THROUGHOUT_PARK_TIP = 3072, + + STR_PLAIN_ENTRANCE = 3078, + STR_WOODEN_ENTRANCE = 3079, + STR_CANVAS_TENT_ENTRANCE = 3080, + STR_CASTLE_ENTRANCE_GREY = 3081, + STR_CASTLE_ENTRANCE_BROWN = 3082, + STR_JUNGLE_ENTRANCE = 3083, + STR_LOG_CABIN_ENTRANCE = 3084, + STR_CLASSICAL_ROMAN_ENTRANCE = 3085, + STR_ABSTRACT_ENTRANCE = 3086, + STR_SNOW_ICE_ENTRANCE = 3087, + STR_PAGODA_ENTRANCE = 3088, + STR_SPACE_ENTRANCE = 3089, + + STR_SELECT_STYLE_OF_ENTRANCE_EXIT_STATION_TIP = 3090, + STR_SELECT_LIFT_HILL_CHAIN_SPEED_TIP = 3097, + STR_SELECT_COLOUR = 3099, STR_SELECT_SECONDARY_COLOUR = 3100, STR_SELECT_TERNARY_COLOUR = 3101, @@ -827,6 +1068,37 @@ enum { STR_LIST_RIDES_TIP = 3104, STR_LIST_SHOPS_AND_STALLS_TIP = 3105, STR_LIST_KIOSKS_AND_FACILITIES_TIP = 3106, + STR_CLOSE_RIDE = 3107, + STR_TEST_RIDE = 3108, + STR_OPEN_RIDE = 3109, + STR_BLOCK_SECTIONS = 3110, + + STR_CLICK_ON_DESIGN_TO_BUILD_IT_TIP = 3111, + STR_CLICK_ON_DESIGN_TO_RENAME_OR_DELETE_IT = 3112, + STR_SELECT_A_DIFFERENT_DESIGN = 3113, + STR_GO_BACK_TO_DESIGN_SELECTION_WINDOW_TIP = 3114, + STR_SAVE_TRACK_DESIGN = 3115, + STR_SAVE_TRACK_DESIGN_NOT_POSSIBLE = 3116, + + STR_CALLING_MECHANIC = 3117, + STR_MEHCANIC_IS_HEADING_FOR_THE_RIDE = 3118, + STR_MEHCANIC_IS_FIXING_THE_RIDE = 3119, + STR_LOCATE_NEAREST_AVAILABLE_MECHANIC_TIP = 3120, + + STR_FAVOURITE_RIDE_OF_GUEST = 3122, + STR_FAVOURITE_RIDE_OF_GUESTS = 3123, + + STR_SAVE_TRACK_DESIGN_ITEM = 3128, + STR_SAVE_TRACK_DESIGN_WITH_SCENERY_ITEM = 3129, + STR_DESIGN_SAVE = 3130, + STR_DESIGN_CANCEL = 3131, + STR_CLICK_ITEMS_OF_SCENERY_TO_SELECT = 3132, + + STR_DESIGN_INCLUDES_SCENERY_WHICH_IS_UNAVAILABLE = 3134, + STR_VEHICLE_DESIGN_UNAVAILABLE = 3135, + STR_THIS_DESIGN_WILL_BE_BUILT_WITH_AN_ALTERNATIVE_VEHICLE_TYPE = 3136, + STR_SELECT_NEARBY_SCENERY = 3137, + STR_RESET_SELECTION = 3138, STR_SCROLL_LEFT_TIP = 3145, STR_SCROLL_RIGHT_TIP = STR_SCROLL_LEFT_TIP + 1, @@ -874,6 +1146,10 @@ enum { STR_ROLLER_COASTER_DESIGNER = 3344, STR_TRACK_DESIGNS_MANAGER = 3345, + STR_NO_TRACK_DESIGNS_OF_THIS_TYPE = 3359, + STR_WARNING = 3360, + STR_TOO_MANY_TRACK_DESIGNS_OF_THIS_TYPE = 3361, + STR_SOUND_FORCED_SOFTWARE_BUFFER_MIXING = 3362, STR_SOUND_FORCED_SOFTWARE_BUFFER_MIXING_TIP = 3363, diff --git a/src/award.c b/src/management/award.c similarity index 96% rename from src/award.c rename to src/management/award.c index e8449a55b3..185e025498 100644 --- a/src/award.c +++ b/src/management/award.c @@ -18,14 +18,15 @@ * along with this program. If not, see . *****************************************************************************/ -#include "addresses.h" +#include "../addresses.h" +#include "../interface/window.h" +#include "../localisation/localisation.h" +#include "../peep/peep.h" +#include "../ride/ride.h" +#include "../scenario.h" +#include "../world/sprite.h" #include "award.h" #include "news_item.h" -#include "peep.h" -#include "ride.h" -#include "scenario.h" -#include "sprite.h" -#include "window.h" #define NEGATIVE 0 #define POSITIVE 1 @@ -474,10 +475,12 @@ static int award_is_deserved_best_custom_designed_rides(int awardType, int activ } /** At least 5 colourful rides and more than half of the rides are colourful. */ +const uint8 dazzling_ride_colours[] = { 5, 14, 20, 30 }; static int award_is_deserved_most_dazzling_ride_colours(int awardType, int activeAwardTypes) { - int i, countedRides, colourfulRides; + int i, j, countedRides, colourfulRides; rct_ride *ride; + uint8 mainTrackColour; if (activeAwardTypes & (1 << PARK_AWARD_MOST_DISAPPOINTING)) return 0; @@ -489,8 +492,14 @@ static int award_is_deserved_most_dazzling_ride_colours(int awardType, int activ continue; countedRides++; - if (ride->var_1BC == 5 || ride->var_1BC == 14 || ride->var_1BC == 20 || ride->var_1BC == 30) - colourfulRides++; + + mainTrackColour = ride->track_colour_main[0]; + for (j = 0; j < countof(dazzling_ride_colours); j++) { + if (mainTrackColour == dazzling_ride_colours[j]) { + colourfulRides++; + break; + } + } } return (colourfulRides >= 5 && colourfulRides >= countedRides - colourfulRides); diff --git a/src/award.h b/src/management/award.h similarity index 98% rename from src/award.h rename to src/management/award.h index aba8cb9456..8e7c965f50 100644 --- a/src/award.h +++ b/src/management/award.h @@ -21,7 +21,7 @@ #ifndef _AWARD_H_ #define _AWARD_H_ -#include "rct2.h" +#include "../common.h" typedef struct { uint16 time; diff --git a/src/finance.c b/src/management/finance.c similarity index 97% rename from src/finance.c rename to src/management/finance.c index efedfdff63..32a10767e4 100644 --- a/src/finance.c +++ b/src/management/finance.c @@ -18,13 +18,13 @@ * along with this program. If not, see . *****************************************************************************/ -#include "addresses.h" +#include "../addresses.h" +#include "../interface/window.h" +#include "../peep/peep.h" +#include "../ride/ride.h" +#include "../world/park.h" +#include "../world/sprite.h" #include "finance.h" -#include "sprite.h" -#include "park.h" -#include "peep.h" -#include "ride.h" -#include "window.h" // Monthly staff wages const money32 wage_table[4] = { @@ -130,7 +130,7 @@ void finance_pay_ride_upkeep() if (ride->status != RIDE_STATUS_CLOSED && !(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY)) { sint16 upkeep = ride->upkeep_cost; if (upkeep != -1) { - ride->var_154 -= upkeep; + ride->total_profit -= upkeep; ride->var_14D |= 2; finance_payment(upkeep, RCT2_EXPENDITURE_TYPE_RIDE_UPKEEP); } diff --git a/src/finance.h b/src/management/finance.h similarity index 98% rename from src/finance.h rename to src/management/finance.h index e839dd3914..f87998ab15 100644 --- a/src/finance.h +++ b/src/management/finance.h @@ -21,7 +21,7 @@ #ifndef _FINANCE_H_ #define _FINANCE_H_ -#include "rct2.h" +#include "../common.h" typedef int rct_expenditure_type; diff --git a/src/marketing.c b/src/management/marketing.c similarity index 86% rename from src/marketing.c rename to src/management/marketing.c index 5d94454cae..0a86b9ed95 100644 --- a/src/marketing.c +++ b/src/management/marketing.c @@ -18,13 +18,12 @@ * along with this program. If not, see . *****************************************************************************/ -#include "addresses.h" +#include "../addresses.h" +#include "../interface/window.h" +#include "../localisation/localisation.h" +#include "../ride/ride.h" #include "marketing.h" #include "news_item.h" -#include "rct2.h" -#include "ride.h" -#include "string_ids.h" -#include "window.h" const money16 AdvertisingCampaignPricePerWeek[] = { MONEY(50,00), // PARK_ENTRY_FREE, @@ -107,28 +106,28 @@ void marketing_set_guest_campaign(rct_peep *peep, int campaign) switch (campaign) { case ADVERTISING_CAMPAIGN_PARK_ENTRY_FREE: peep->item_standard_flags |= PEEP_ITEM_VOUCHER; - peep->var_F0 = 0; + peep->voucher_type = VOUCHER_TYPE_PARK_ENTRY_FREE; break; case ADVERTISING_CAMPAIGN_RIDE_FREE: peep->item_standard_flags |= PEEP_ITEM_VOUCHER; - peep->var_F0 = 1; - peep->var_F1 = RCT2_ADDRESS(0x01358116, uint8)[campaign]; - peep->var_C5 = RCT2_ADDRESS(0x01358116, uint8)[campaign]; + peep->voucher_type = VOUCHER_TYPE_RIDE_FREE; + peep->voucher_arguments = RCT2_ADDRESS(0x01358116, uint8)[campaign]; + peep->guest_heading_to_ride_id = RCT2_ADDRESS(0x01358116, uint8)[campaign]; peep->var_C6 = 240; break; case ADVERTISING_CAMPAIGN_PARK_ENTRY_HALF_PRICE: peep->item_standard_flags |= PEEP_ITEM_VOUCHER; - peep->var_F0 = 2; + peep->voucher_type = VOUCHER_TYPE_PARK_ENTRY_HALF_PRICE; break; case ADVERTISING_CAMPAIGN_FOOD_OR_DRINK_FREE: peep->item_standard_flags |= PEEP_ITEM_VOUCHER; - peep->var_F0 = 3; - peep->var_F1 = RCT2_ADDRESS(0x01358116, uint8)[campaign]; + peep->voucher_type = VOUCHER_TYPE_FOOD_OR_DRINK_FREE; + peep->voucher_arguments = RCT2_ADDRESS(0x01358116, uint8)[campaign]; break; case ADVERTISING_CAMPAIGN_PARK: break; case ADVERTISING_CAMPAIGN_RIDE: - peep->var_C5 = RCT2_ADDRESS(0x01358116, uint8)[campaign]; + peep->guest_heading_to_ride_id = RCT2_ADDRESS(0x01358116, uint8)[campaign]; peep->var_C6 = 240; break; } diff --git a/src/marketing.h b/src/management/marketing.h similarity index 88% rename from src/marketing.h rename to src/management/marketing.h index f5ee816d3d..6435256cb4 100644 --- a/src/marketing.h +++ b/src/management/marketing.h @@ -21,7 +21,8 @@ #ifndef _MARKETING_H_ #define _MARKETING_H_ -#include "peep.h" +#include "../common.h" +#include "../peep/peep.h" enum { ADVERTISING_CAMPAIGN_PARK_ENTRY_FREE, @@ -33,6 +34,13 @@ enum { ADVERTISING_CAMPAIGN_COUNT }; +enum{ + VOUCHER_TYPE_PARK_ENTRY_FREE, + VOUCHER_TYPE_RIDE_FREE, + VOUCHER_TYPE_PARK_ENTRY_HALF_PRICE, + VOUCHER_TYPE_FOOD_OR_DRINK_FREE, +}; + extern const money16 AdvertisingCampaignPricePerWeek[6]; int marketing_get_campaign_guest_generation_probability(int campaign); diff --git a/src/news_item.c b/src/management/news_item.c similarity index 92% rename from src/news_item.c rename to src/management/news_item.c index 986502d1fe..885b3c4ed0 100644 --- a/src/news_item.c +++ b/src/management/news_item.c @@ -19,15 +19,14 @@ *****************************************************************************/ #include -#include "addresses.h" -#include "audio.h" -#include "date.h" +#include "../addresses.h" +#include "../audio/audio.h" +#include "../interface/window.h" +#include "../localisation/date.h" +#include "../localisation/localisation.h" +#include "../ride/ride.h" +#include "../world/sprite.h" #include "news_item.h" -#include "rct2.h" -#include "ride.h" -#include "string_ids.h" -#include "sprite.h" -#include "window.h" void window_game_bottom_toolbar_invalidate_news_item(); static int news_item_get_new_history_slot(); @@ -97,7 +96,7 @@ void news_item_update_current() newsItems[0].ticks++; if (newsItems[0].ticks == 1 && !(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 1)) { // Play sound - sound_play_panned(SOUND_NEWS_ITEM, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) / 2); + sound_play_panned(SOUND_NEWS_ITEM, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) / 2, 0, 0, 0); } // Removal of current news item @@ -212,7 +211,7 @@ void news_item_get_subject_location(int type, int subject, int *x, int *y, int * } // Find the first car of the train peep is on - vehicle = &(g_sprite_list[ride->train_car_map[peep->current_train]]).vehicle; + vehicle = &(g_sprite_list[ride->vehicles[peep->current_train]]).vehicle; // Find the actual car peep is on for (i = 0; i < peep->current_car; i++) vehicle = &(g_sprite_list[vehicle->next_vehicle_on_train]).vehicle; @@ -252,7 +251,7 @@ void news_item_add_to_queue(uint8 type, rct_string_id string_id, uint32 assoc) // find first open slot while (newsItem->type != NEWS_ITEM_NULL) { - if (newsItem + sizeof(newsItem) >= (rct_news_item*)0x13CB1CC) + if (newsItem + 1 >= (rct_news_item*)0x13CB1CC) news_item_close_current(); else newsItem++; @@ -283,15 +282,14 @@ void news_item_add_to_queue(uint8 type, rct_string_id string_id, uint32 assoc) * rct2: 0x0066EBE6 * **/ -void news_item_open_subject(int type, int subject) { - - int eax; +void news_item_open_subject(int type, int subject) +{ rct_peep* peep; rct_window* window; switch (type) { case NEWS_ITEM_RIDE: - RCT2_CALLPROC_X(0x006ACC28, subject, 0, 0, 0, 0, 0, 0); + window_ride_main_open(subject); break; case NEWS_ITEM_PEEP_ON_RIDE: case NEWS_ITEM_PEEP: @@ -302,14 +300,15 @@ void news_item_open_subject(int type, int subject) { window_finances_open(); break; case NEWS_ITEM_RESEARCH: - if (subject >= 0x10000) { // Open ride list window - RCT2_CALLPROC_EBPSAFE(0x006B3CFF); - eax = (subject & 0xFF00) >> 8; - eax += (subject & 0xFF) << 8; + window_new_ride_open(); + // Switch to right tab and scroll to ride location - RCT2_CALLPROC_X(0x006B3EBA, eax, 0, subject, 0, 0, 0, 0); + ride_list_item rideItem; + rideItem.type = subject >> 8; + rideItem.entry_index = subject & 0xFF; + window_new_ride_focus(rideItem); break; } @@ -323,13 +322,12 @@ void news_item_open_subject(int type, int subject) { RCT2_CALLPROC_X(0x006E1172, (subject & 0xFFFF), 0, subject, 0, 0, 0, 0); } RCT2_GLOBAL(0x009DE518, uint32) |= (1 << 6); - // Open scenery window - RCT2_CALLPROC_EBPSAFE(0x006E0FEF); + window_scenery_open(); } } + // Switch to new scenery tab RCT2_CALLPROC_X(0x006E1172, (subject & 0xFFFF), 0, subject, 0, 0, 0, 0); - break; case NEWS_ITEM_PEEPS: // Open guest list to right tab diff --git a/src/news_item.h b/src/management/news_item.h similarity index 96% rename from src/news_item.h rename to src/management/news_item.h index a089496741..8b48e61b6b 100644 --- a/src/news_item.h +++ b/src/management/news_item.h @@ -21,10 +21,7 @@ #ifndef _NEWS_ITEM_H_ #define _NEWS_ITEM_H_ -#include "rct2.h" -#include "map.h" -#include "string_ids.h" - +#include "../common.h" enum { NEWS_ITEM_NULL, diff --git a/src/management/research.c b/src/management/research.c new file mode 100644 index 0000000000..9d71a0b95d --- /dev/null +++ b/src/management/research.c @@ -0,0 +1,262 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of OpenRCT2. + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#include "../addresses.h" +#include "../interface/window.h" +#include "../localisation/date.h" +#include "../world/scenery.h" +#include "news_item.h" +#include "research.h" + +const int _researchRate[] = { 0, 160, 250, 400 }; + +// 0x01358844[500] +extern rct_research_item *gResearchItems = (rct_research_item*)RCT2_RESEARCH_ITEMS; + +// 0x00EE787C +uint8 gResearchUncompletedCategories; + +/** + * + * rct2: 0x006671AD, part of 0x00667132 + */ +void research_reset_items() +{ + gResearchItems[0].entryIndex = RESEARCHED_ITEMS_SEPERATOR; + gResearchItems[1].entryIndex = RESEARCHED_ITEMS_END; + gResearchItems[2].entryIndex = -3; +} + +/** + * + * rct2: 0x00684BAE + */ +void research_update_uncompleted_types() +{ + int uncompletedResearchTypes = 0; + rct_research_item *researchItem = gResearchItems; + while (researchItem->entryIndex != -1) + researchItem++; + researchItem++; + for (; researchItem->entryIndex != -2; researchItem++) + uncompletedResearchTypes |= (1 << researchItem->category); + + gResearchUncompletedCategories = uncompletedResearchTypes; +} + +/** + * + * rct2: 0x00684D2A + */ +static void research_calculate_expected_date() +{ + int progress = RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS, uint16); + int progressStage = RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8); + int researchLevel = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_RESEARCH_LEVEL, uint8); + int currentDay = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_TICKS, uint16); + int currentMonth = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, uint16); + int expectedDay, expectedMonth, dayQuotient, dayRemainder, progressRemaining, daysRemaining; + + if (progressStage == RESEARCH_STAGE_INITIAL_RESEARCH || researchLevel == RESEARCH_FUNDING_NONE) { + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_EXPECTED_DAY, uint8) = 255; + } else { + progressRemaining = progressStage == RESEARCH_STAGE_COMPLETING_DESIGN ? 0x10000 : 0x20000; + progressRemaining -= progress; + daysRemaining = (progressRemaining / _researchRate[researchLevel]) * 128; + + expectedDay = currentDay + (daysRemaining & 0xFFFF); + dayQuotient = expectedDay / 0x10000; + dayRemainder = expectedDay % 0x10000; + + expectedMonth = date_get_month(currentMonth + dayQuotient + (daysRemaining >> 16)); + expectedDay = (dayRemainder * days_in_month[expectedMonth]) >> 16; + + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_EXPECTED_DAY, uint8) = expectedDay; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_EXPECTED_MONTH, uint8) = expectedMonth; + } +} + +static void research_invalidate_related_windows() +{ + window_invalidate_by_id(WC_CONSTRUCT_RIDE, 0); + window_invalidate_by_id(WC_RESEARCH, 0); +} + +/** + * + * rct2: 0x00684BE5 + */ +static void research_next_design() +{ + rct_research_item *firstUnresearchedItem, *researchItem, tmp; + int ignoreActiveResearchTypes; + int activeResearchTypes = RCT2_GLOBAL(RCT2_ADDRESS_ACTIVE_RESEARCH_TYPES, uint16); + + // Skip already researched items + firstUnresearchedItem = gResearchItems; + while (firstUnresearchedItem->entryIndex != RESEARCHED_ITEMS_SEPERATOR) + firstUnresearchedItem++; + + ignoreActiveResearchTypes = 0; + researchItem = firstUnresearchedItem; + for (;;) { + researchItem++; + if (researchItem->entryIndex == RESEARCHED_ITEMS_END) { + if (!ignoreActiveResearchTypes) { + ignoreActiveResearchTypes = 1; + researchItem = firstUnresearchedItem; + continue; + } else { + RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS, uint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8) = RESEARCH_STAGE_INITIAL_RESEARCH; + research_invalidate_related_windows(); + return; + } + } else if (ignoreActiveResearchTypes || (activeResearchTypes & (1 << researchItem->category))) { + break; + } + } + + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_ITEM, uint32) = researchItem->entryIndex; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_CATEGORY, uint8) = researchItem->category; + RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS, uint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8) = RESEARCH_STAGE_DESIGNING; + + // Bubble research item up until it is above the researched items seperator + do { + tmp = *researchItem; + *researchItem = *(researchItem - 1); + *(researchItem - 1) = tmp; + researchItem--; + } while ((researchItem + 1)->entryIndex != RESEARCHED_ITEMS_SEPERATOR); + + research_invalidate_related_windows(); +} + +/** + * + * rct2: 0x006848D4 + */ +void research_finish_item(sint32 entryIndex) +{ + int i, ebx, ecx, rideEntryIndex, subSceneryEntryIndex; + rct_ride_type *rideEntry, *rideEntry2; + rct_scenery_set_entry *scenerySetEntry; + + RCT2_GLOBAL(RCT2_ADDRESS_LAST_RESEARCHED_ITEM_SUBJECT, sint32) = entryIndex; + research_invalidate_related_windows(); + if (entryIndex >= 0x10000) { + // Ride + ecx = (entryIndex >> 8) & 0xFF; + rideEntryIndex = entryIndex & 0xFF; + rideEntry = GET_RIDE_ENTRY(rideEntryIndex); + RCT2_ADDRESS(0x01357404, uint32)[ecx >> 5] |= (1 << (ecx & 0x1F)); + RCT2_ADDRESS(0x01357444, uint32)[ecx] = RCT2_ADDRESS(0x0097C468, uint32)[ecx]; + RCT2_ADDRESS(0x01357644, uint32)[ecx] = RCT2_ADDRESS(0x0097C5D4, uint32)[ecx]; + if (RCT2_GLOBAL(0x0097D4F2 + (ecx * 8), uint16) & 8) { + ebx = RCT2_GLOBAL(0x0097D4F5 + (ecx * 8), uint8); + RCT2_ADDRESS(0x01357444, uint32)[ebx] = RCT2_ADDRESS(0x0097C468, uint32)[ebx]; + RCT2_ADDRESS(0x01357644, uint32)[ebx] = RCT2_ADDRESS(0x0097C5D4, uint32)[ebx]; + } + RCT2_ADDRESS(0x001357424, uint32)[rideEntryIndex >> 5] |= 1 << (rideEntryIndex & 0x1F); + if (!(rideEntry->var_008 & 0x2000)) { + for (i = 0; i < 128; i++) { + rideEntry2 = GET_RIDE_ENTRY(i); + if (rideEntry2 == (rct_ride_type*)-1) + continue; + if (rideEntry2->var_008 & 0x2000) + continue; + + if (rideEntry2->var_00C == ecx || rideEntry2->var_00D == ecx || rideEntry2->var_00E == ecx) + RCT2_ADDRESS(0x001357424, uint32)[i >> 5] |= 1 << (i & 0x1F); + } + } + + // I don't think 0x009AC06C is ever not 0, so probably redundant + if (RCT2_GLOBAL(0x009AC06C, uint8) == 0) { + RCT2_GLOBAL(0x013CE952, rct_string_id) = rideEntry->var_008 & 0x1000 ? + rideEntry->name : ecx + 2; + news_item_add_to_queue(NEWS_ITEM_RESEARCH, 2249, entryIndex); + } + + research_invalidate_related_windows(); + } else { + // Scenery + scenerySetEntry = g_scenerySetEntries[entryIndex & 0xFFFF]; + for (i = 0; i < scenerySetEntry->entry_count; i++) { + subSceneryEntryIndex = scenerySetEntry->scenery_entries[i]; + RCT2_ADDRESS(0x01357BD0, sint32)[subSceneryEntryIndex >> 5] |= 1 << (subSceneryEntryIndex & 0x1F); + } + + // I don't think 0x009AC06C is ever not 0, so probably redundant + if (RCT2_GLOBAL(0x009AC06C, uint8) == 0) { + RCT2_GLOBAL(0x013CE952, rct_string_id) = scenerySetEntry->name; + news_item_add_to_queue(NEWS_ITEM_RESEARCH, 2250, entryIndex); + } + + research_invalidate_related_windows(); + init_scenery(); + } +} + +/** + * + * rct2: 0x00684C7A + */ +void research_update() +{ + int editorScreenFlags, researchLevel, currentResearchProgress; + + editorScreenFlags = SCREEN_FLAGS_SCENARIO_EDITOR | SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER; + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & editorScreenFlags) + return; + + if (RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, uint32) % 32 != 0) + return; + + researchLevel = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_RESEARCH_LEVEL, uint8); + + currentResearchProgress = RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS, uint16); + currentResearchProgress += _researchRate[researchLevel]; + if (currentResearchProgress <= 0xFFFF) { + RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS, uint16) = currentResearchProgress; + } else { + switch (RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8)) { + case RESEARCH_STAGE_INITIAL_RESEARCH: + research_next_design(); + research_calculate_expected_date(); + break; + case RESEARCH_STAGE_DESIGNING: + RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS, uint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8) = RESEARCH_STAGE_COMPLETING_DESIGN; + research_calculate_expected_date(); + research_invalidate_related_windows(); + break; + case RESEARCH_STAGE_COMPLETING_DESIGN: + research_finish_item(RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_ITEM, sint32)); + RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS, uint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8) = 0; + research_calculate_expected_date(); + research_update_uncompleted_types(); + research_invalidate_related_windows(); + break; + } + } +} \ No newline at end of file diff --git a/src/management/research.h b/src/management/research.h new file mode 100644 index 0000000000..1194798dd8 --- /dev/null +++ b/src/management/research.h @@ -0,0 +1,56 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of OpenRCT2. + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#ifndef _RESEARCH_H_ +#define _RESEARCH_H_ + +#include "../common.h" + +typedef struct { + // Bit 16 (0: scenery entry, 1: ride entry) + sint32 entryIndex; + uint8 category; +} rct_research_item; + +#define RESEARCHED_ITEMS_SEPERATOR -1 +#define RESEARCHED_ITEMS_END -2 + +enum { + RESEARCH_FUNDING_NONE, + RESEARCH_FUNDING_MINIMUM, + RESEARCH_FUNDING_NORMAL, + RESEARCH_FUNDING_MAXIMUM +}; + +enum { + RESEARCH_STAGE_INITIAL_RESEARCH, + RESEARCH_STAGE_DESIGNING, + RESEARCH_STAGE_COMPLETING_DESIGN, + RESEARCH_STAGE_UNKNOWN +}; + +extern rct_research_item *gResearchItems; +extern uint8 gResearchUncompletedCategories; + +void research_reset_items(); +void research_update_uncompleted_types(); +void research_update(); + +#endif \ No newline at end of file diff --git a/src/object.c b/src/object.c index 1df31a9b79..a4644602f7 100644 --- a/src/object.c +++ b/src/object.c @@ -20,25 +20,276 @@ #include #include +#include +#include #include "addresses.h" +#include "localisation/localisation.h" #include "object.h" -#include "sawyercoding.h" +#include "platform/osinterface.h" +#include "util/sawyercoding.h" +int object_entry_compare(rct_object_entry *a, rct_object_entry *b); +int object_calculate_checksum(rct_object_entry *entry, char *data, int dataLength); +int object_paint(int type, int eax, int ebx, int ecx, int edx, int esi, int edi, int ebp); +rct_object_entry *object_get_next(rct_object_entry *entry); /** * * rct2: 0x006A985D */ int object_load(int groupIndex, rct_object_entry *entry) { - RCT2_CALLPROC_X(0x006A985D, 0, 0, groupIndex, 0, 0, 0, (int)entry); - #ifdef _MSC_VER - __asm jb fail - #else - __asm__ goto ( "jb %l0" : : : : fail ); - #endif - return 1; -fail: + RCT2_GLOBAL(0xF42B64, uint32) = groupIndex; + + //part of 6a9866 + rct_object_entry *installedObject = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); + + if (!(RCT2_GLOBAL(0xF42B6C, uint32))){ + RCT2_GLOBAL(0xF42BD9, uint8) = 0; + return 1; + } + for (int i = 0; i < RCT2_GLOBAL(0x00F42B6C, sint32); i++) { + if (object_entry_compare(installedObject, entry)){ + + char path[260]; + char *objectPath = (char*)installedObject + 16; + subsitute_path(path, RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char), objectPath); + rct_object_entry openedEntry; + FILE *file = fopen(path, "rb"); + if (file != NULL) { + fread(&openedEntry, sizeof(rct_object_entry), 1, file); + if (object_entry_compare(&openedEntry, entry)) { + + // Get chunk size + char *pos = (char*)installedObject + 16; + do { + pos++; + } while (*(pos - 1) != 0); + + // Read chunk + int chunkSize = *((uint32*)pos); + char *chunk; + + if (chunkSize == 0xFFFFFFFF) { + chunk = rct2_malloc(0x600000); + chunkSize = sawyercoding_read_chunk(file, chunk); + chunk = rct2_realloc(chunk, chunkSize); + } + else { + chunk = rct2_malloc(chunkSize); + chunkSize = sawyercoding_read_chunk(file, chunk); + } + fclose(file); + + // Calculate and check checksum + if (object_calculate_checksum(&openedEntry, chunk, chunkSize) != openedEntry.checksum) { + RCT2_GLOBAL(0x00F42BD9, uint8) = 2; + rct2_free(chunk); + return 0; + } + + if (object_paint(openedEntry.flags & 0x0F, 2, 0, openedEntry.flags & 0x0F, 0, (int)chunk, 0, 0)) { + RCT2_GLOBAL(0x00F42BD9, uint8) = 3; + rct2_free(chunk); + return 0; + } + + int yyy = RCT2_GLOBAL(0x009ADAF0, uint32); + + if (yyy >= 0x4726E){ + RCT2_GLOBAL(0x00F42BD9, uint8) = 4; + rct2_free(chunk); + return 0; + } + //B84 is openedEntry + int ebp = openedEntry.flags & 0x0F; + int esi = RCT2_ADDRESS(0x98D97C, uint32)[ebp * 2]; + int ecx = groupIndex; + if (ecx == -1){ + for (int ecx = 0; ((sint32*)esi)[ecx] != -1; ecx++){ + if ((ecx + 1) >= object_entry_group_counts[ebp]){ + RCT2_GLOBAL(0x00F42BD9, uint8) = 5; + rct2_free(chunk); + return 0; + } + } + } + ((char**)esi)[ecx] = chunk; + + int* edx = (int*)( ecx * 20 + RCT2_ADDRESS(0x98D980, uint32)[ebp * 2]); + memcpy(edx, (int*)&openedEntry, 20); + if (RCT2_GLOBAL(0x9ADAFD, uint8) == 0)return 1; + object_paint(ecx, 0, ecx, ebp, 0, (int)chunk, 0, 0); + return 1; + } + fclose(file); + } + } + installedObject = object_get_next(installedObject); + } + //6a991f + // Installed Object can not be found. return 0; + //return !(RCT2_CALLPROC_X(0x006A985D, 0, 0, groupIndex, 0, 0, 0, (int)entry) & 0x400); +} + +/** rct2: 0x006a9f42 + * ebx : file + * ebp : entry + */ +int sub_6A9F42(FILE *file, rct_object_entry* entry){ + int eax = 0, entryGroupIndex = 0, type = 0, edx = 0, edi = 0, ebp = (int)entry, chunk = 0; + RCT2_CALLFUNC_X(0x6A9DA2, &eax, &entryGroupIndex, &type, &edx, &chunk, &edi, &ebp); + if (eax == 0) return 0; + + object_paint(type, 1, entryGroupIndex, type, edx, chunk, edi, ebp); + + + rct_object_entry* installed_entry = (rct_object_entry*)(entryGroupIndex * 20 + RCT2_ADDRESS(0x98D980, uint32)[type * 2]); + uint8* dst_buffer = malloc(0x600000); + memcpy(dst_buffer, (void*)installed_entry, 16); + + uint32 size_dst = 16; + + sawyercoding_chunk_header chunkHeader; + // Encoding type (not used anymore) + RCT2_GLOBAL(0x9E3CBD, uint8) = object_entry_group_encoding[type]; + + chunkHeader.encoding = object_entry_group_encoding[type]; + chunkHeader.length = *(uint32*)(((uint8*)installed_entry + 16)); + + size_dst += sawyercoding_write_chunk_buffer(dst_buffer+16, (uint8*)chunk, chunkHeader); + fwrite(dst_buffer, 1, size_dst, file); + + free(dst_buffer); +} + +/** +* +* rct2: 0x006AA2B7 +*/ +int object_load_packed(FILE *file) +{ + object_unload_all(); + + rct_object_entry* entry = RCT2_ADDRESS(0xF42B84, rct_object_entry); + + fread((void*)entry, 16, 1, file); + + uint8* chunk = rct2_malloc(0x600000); + uint32 chunkSize = sawyercoding_read_chunk(file, chunk); + chunk = rct2_realloc(chunk, chunkSize); + if (chunk == NULL){ + return 0; + } + + if (object_calculate_checksum(entry, chunk, chunkSize) != entry->checksum){ + rct2_free(chunk); + return 0; + } + + if (object_paint(entry->flags & 0x0F, 2, 0, entry->flags & 0x0F, 0, (int)chunk, 0, 0)) { + rct2_free(chunk); + return 0; + } + + int yyy = RCT2_GLOBAL(0x009ADAF0, uint32); + + if (yyy >= 0x4726E){ + rct2_free(chunk); + return 0; + } + + int type = entry->flags & 0x0F; + + // ecx + int entryGroupIndex = 0; + + for (; entryGroupIndex < object_entry_group_counts[type]; entryGroupIndex++){ + if (RCT2_ADDRESS(0x98D97C, uint32*)[type * 2][entryGroupIndex] == -1){ + break; + } + } + + if (entryGroupIndex == object_entry_group_counts[type]){ + rct2_free(chunk); + return 0; + } + + RCT2_ADDRESS(0x98D97C, uint8**)[type * 2][entryGroupIndex] = chunk; + int* edx = (int*)(entryGroupIndex * 20 + RCT2_ADDRESS(0x98D980, uint32)[type * 2]); + memcpy(edx, (int*)entry, 16); + *(edx + 4) = chunkSize; + + //esi + rct_object_entry *installedObject = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); + + if (RCT2_GLOBAL(0xF42B6C, uint32)){ + for (uint32 i = 0; i < RCT2_GLOBAL(0xF42B6C, uint32); ++i){ + if (object_entry_compare(entry, installedObject)){ + object_unload_all(); + return 0; + } + installedObject = object_get_next(installedObject); + } + } + + //Installing new data + //format_string(0x141ED68, 3163, 0); + //Code for updating progress bar removed. + + char path[260]; + char objectPath[13] = { 0 }; + for (int i = 0; i < 8; ++i){ + if (entry->name[i] != ' ') + objectPath[i] = toupper(entry->name[i]); + else + objectPath[i] = '\0'; + } + + subsitute_path(path, RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char), objectPath); + char* last_char = path + strlen(path); + strcat(path, ".DAT"); + + // + for (; osinterface_file_exists(path);){ + for (char* curr_char = last_char - 1;; --curr_char){ + if (*curr_char == '\\'){ + subsitute_path(path, RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char), "00000000.DAT"); + char* last_char = path + strlen(path); + break; + } + if (*curr_char < '0') *curr_char = '0'; + else if (*curr_char == '9') *curr_char = 'A'; + else if (*curr_char == 'Z') *curr_char = '0'; + else (*curr_char)++; + if (*curr_char != '0') break; + } + } + + // Removed progress bar code + + // The following section cannot be finished until 6A9F42 is finished + // Run the game once with vanila rct2 to not reach this part of code. + RCT2_ERROR("Function not finished. Please run this save once with vanila rct2."); + FILE* obj_file = fopen(path, "wb"); + if (obj_file){ + // Removed progress bar code + sub_6A9F42(obj_file, entry); + fclose(obj_file); + // Removed progress bar code + object_unload_all(); + // Removed progress bar code + return 1; + } + else{ + object_unload_all(); + return 0; + } + //create file + //6aa48C + int eax = 1;//, ebx = 0, ecx = 0, edx = 0, esi = 0, edi = 0, ebp = 0; + //RCT2_CALLFUNC_X(0x006AA2B7, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + return eax; } /** @@ -50,7 +301,7 @@ void object_unload(int groupIndex, rct_object_entry_extended *entry) RCT2_CALLPROC_X(0x006A9CAF, 0, groupIndex, 0, 0, 0, 0, (int)entry); } -static int object_entry_compare(rct_object_entry *a, rct_object_entry *b) +int object_entry_compare(rct_object_entry *a, rct_object_entry *b) { if (a->flags & 0xF0) { if ((a->flags & 0x0F) != (b->flags & 0x0F)) @@ -73,7 +324,7 @@ static int object_entry_compare(rct_object_entry *a, rct_object_entry *b) return 1; } -static int object_calculate_checksum(rct_object_entry *entry, char *data, int dataLength) +int object_calculate_checksum(rct_object_entry *entry, char *data, int dataLength) { int i; char *eee = (char*)entry; @@ -122,15 +373,7 @@ int object_paint(int type, int eax, int ebx, int ecx, int edx, int esi, int edi, if (type == 10){ if (eax == 0) return object_scenario_load_custom_text((char*)esi); } - RCT2_CALLPROC_X(RCT2_ADDRESS(0x0098D9D4, uint32)[type], eax, ebx, ecx, edx, esi, edi, ebp); - #ifdef _MSC_VER - __asm jb success - #else - __asm__ goto ( "jb %l0" : : : : success ); - #endif - return 0; -success: - return 1; + return RCT2_CALLPROC_X(RCT2_ADDRESS(0x0098D9D4, uint32)[type], eax, ebx, ecx, edx, esi, edi, ebp) & 0x100; } /** @@ -231,7 +474,7 @@ rct_object_entry *object_get_next(rct_object_entry *entry) { char *pos = (char*)entry; - // Skip + // Skip sizeof(rct_object_entry) pos += 16; // Skip filename @@ -247,7 +490,7 @@ rct_object_entry *object_get_next(rct_object_entry *entry) pos++; } while (*(pos - 1) != 0); - // Skip + // Skip size of chunk pos += 4; // Skip @@ -260,4 +503,4 @@ rct_object_entry *object_get_next(rct_object_entry *entry) pos += 4; return (rct_object_entry*)pos; -} \ No newline at end of file +} diff --git a/src/object.h b/src/object.h index a9d8bdbdfc..b0e125ae8d 100644 --- a/src/object.h +++ b/src/object.h @@ -45,9 +45,12 @@ typedef struct { uint32 extended; } rct_object_entry_extended; +extern int object_entry_group_counts[]; +extern int object_entry_group_encoding[]; + void object_list_load(); -void object_read_and_load_entries(FILE *file); -int object_load_packed(); +int object_read_and_load_entries(FILE *file); +int object_load_packed(FILE *file); void object_unload_all(); int object_load(int groupIndex, rct_object_entry *entry); @@ -56,5 +59,7 @@ int object_get_scenario_text(rct_object_entry *entry); void object_free_scenario_text(); int object_get_length(rct_object_entry *entry); rct_object_entry *object_get_next(rct_object_entry *entry); +int object_calculate_checksum(rct_object_entry *entry, char *data, int dataLength); +int object_paint(int type, int eax, int ebx, int ecx, int edx, int esi, int edi, int ebp); #endif diff --git a/src/object_list.c b/src/object_list.c index 78d5686d07..4ddcf45712 100644 --- a/src/object_list.c +++ b/src/object_list.c @@ -21,7 +21,7 @@ #include #include "addresses.h" #include "object.h" -#include "sawyercoding.h" +#include "util/sawyercoding.h" #define OBJECT_ENTRY_GROUP_COUNT 11 #define OBJECT_ENTRY_COUNT 721 @@ -34,6 +34,7 @@ typedef struct { uint32 var_10; } rct_plugin_header; +// 98DA00 int object_entry_group_counts[] = { 128, // rides 252, // small scenery @@ -48,6 +49,21 @@ int object_entry_group_counts[] = { 1 // scenario text }; +// 98DA2C +int object_entry_group_encoding[] = { + CHUNK_ENCODING_RLE, + CHUNK_ENCODING_RLE, + CHUNK_ENCODING_RLE, + CHUNK_ENCODING_RLE, + CHUNK_ENCODING_RLE, + CHUNK_ENCODING_RLE, + CHUNK_ENCODING_RLE, + CHUNK_ENCODING_RLE, + CHUNK_ENCODING_RLE, + CHUNK_ENCODING_RLE, + CHUNK_ENCODING_ROTATE +}; + struct { void **data; rct_object_entry_extended *entries; } object_entry_groups[] = { (void**)(0x009ACFA4 ), (rct_object_entry_extended*)(0x00F3F03C ), // rides (void**)(0x009ACFA4 + (128 * 4)), (rct_object_entry_extended*)(0x00F3F03C + (128 * 20)), // small scenery @@ -157,7 +173,7 @@ static int check_object_entry(rct_object_entry *entry) * * rct2: 0x006AA0C6 */ -void object_read_and_load_entries(FILE *file) +int object_read_and_load_entries(FILE *file) { object_unload_all(); @@ -184,26 +200,21 @@ void object_read_and_load_entries(FILE *file) // Load the obect if (!object_load(entryGroupIndex, &entries[i])) { // Failed to load the object - free(entries); + //Destroy progress bar + memcpy((char*)0x13CE952, entries[i].name, 8); + free(entries); object_unload_all(); - return; + RCT2_GLOBAL(0x14241BC, uint32) = 0; + return 0; } } free(entries); + return 1; } -/** - * - * rct2: 0x006AA2B7 - */ -int object_load_packed() -{ - int eax, ebx, ecx, edx, esi, edi, ebp; - RCT2_CALLFUNC_X(0x006AA2B7, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - return eax; -} + /** * @@ -217,4 +228,4 @@ void object_unload_all() for (j = 0; j < object_entry_group_counts[i]; j++) if (object_entry_groups[i].data[j] != (void**)0xFFFFFFFF) object_unload(j, &object_entry_groups[i].entries[j]); -} \ No newline at end of file +} diff --git a/src/peep.c b/src/peep/peep.c similarity index 76% rename from src/peep.c rename to src/peep/peep.c index aa2d252b6a..7412b278f5 100644 --- a/src/peep.c +++ b/src/peep/peep.c @@ -19,17 +19,49 @@ *****************************************************************************/ #include -#include "addresses.h" -#include "audio.h" -#include "news_item.h" +#include "../addresses.h" +#include "../audio/audio.h" +#include "../audio/mixer.h" +#include "../interface/window.h" +#include "../localisation/localisation.h" +#include "../management/news_item.h" +#include "../ride/ride.h" +#include "../sprites.h" +#include "../world/sprite.h" #include "peep.h" -#include "rct2.h" -#include "ride.h" -#include "sprite.h" -#include "window.h" +#include "staff.h" static void peep_update(rct_peep *peep); +const char *gPeepEasterEggNames[] = { + "MICHAEL SCHUMACHER", + "JACQUES VILLENEUVE", + "DAMON HILL", + "MR BEAN", + "CHRIS SAWYER", + "KATIE BRAYSHAW", + "MELANIE WARN", + "SIMON FOSTER", + "JOHN WARDLEY", + "LISA STIRLING", + "DONALD MACRAE", + "KATHERINE MCGOWAN", + "FRANCES MCGOWAN", + "CORINA MASSOURA", + "CAROL YOUNG", + "MIA SHERIDAN", + "KATIE RODGER", + "EMMA GARRELL", + "JOANNE BARTON", + "FELICITY ANDERSON", + "KATIE SMITH", + "EILIDH BELL", + "NANCY STILLWAGON", + "ANDY HINE", + "ELISSA WHITE", + "DAVID ELLIS" +}; + int peep_get_staff_count() { uint16 spriteIndex; @@ -177,31 +209,31 @@ void peep_problem_warnings_update() break; case PEEP_THOUGHT_TYPE_HUNGRY: // 0x14 - if (peep->var_C5 == -1){ + if (peep->guest_heading_to_ride_id == -1){ hunger_counter++; break; } - ride = &g_ride_list[peep->var_C5]; + ride = &g_ride_list[peep->guest_heading_to_ride_id]; if (!(RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + ride->type * 8, uint32) & 0x80000)) hunger_counter++; break; case PEEP_THOUGHT_TYPE_THIRSTY: - if (peep->var_C5 == -1){ + if (peep->guest_heading_to_ride_id == -1){ thirst_counter++; break; } - ride = &g_ride_list[peep->var_C5]; + ride = &g_ride_list[peep->guest_heading_to_ride_id]; if (!(RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + ride->type * 8, uint32) & 0x1000000)) thirst_counter++; break; case PEEP_THOUGHT_TYPE_BATHROOM: - if (peep->var_C5 == -1){ + if (peep->guest_heading_to_ride_id == -1){ bathroom_counter++; break; } - ride = &g_ride_list[peep->var_C5]; + ride = &g_ride_list[peep->guest_heading_to_ride_id]; if (!(RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + ride->type * 8, uint32) & 0x2000000)) bathroom_counter++; break; @@ -307,7 +339,7 @@ void peep_update_crowd_noise() visiblePeeps = 0; FOR_ALL_GUESTS(spriteIndex, peep) { - if (peep->var_16 == 0x8000) + if (peep->var_16 == (sint16)0x8000) continue; if (viewport->view_x > peep->var_1A) continue; @@ -330,7 +362,12 @@ void peep_update_crowd_noise() if (visiblePeeps < 0) { // Mute crowd noise if (RCT2_GLOBAL(0x009AF5FC, uint32) != 1) { +#ifdef USE_MIXER + Mixer_Stop_Channel(gMusicChannels[2]); + gMusicChannels[2] = 0; +#else sound_channel_stop(2); //RCT2_CALLPROC_1(0x00401A05, int, 2); +#endif RCT2_GLOBAL(0x009AF5FC, uint32) = 1; } } else { @@ -345,14 +382,26 @@ void peep_update_crowd_noise() // Check if crowd noise is already playing if (RCT2_GLOBAL(0x009AF5FC, uint32) == 1) { // Load and play crowd noise +#ifdef USE_MIXER + gMusicChannels[2] = Mixer_Play_Music(PATH_ID_CSS2); + if (gMusicChannels[2]) { + Mixer_Channel_Volume(gMusicChannels[2], DStoMixerVolume(volume)); + RCT2_GLOBAL(0x009AF5FC, uint32) = volume; + } +#else if (sound_channel_load_file2(2, (char*)get_file_path(PATH_ID_CSS2), 0)) { sound_channel_play(2, 1, volume, 0, 0); RCT2_GLOBAL(0x009AF5FC, uint32) = volume; } +#endif } else { // Alter crowd noise volume if (RCT2_GLOBAL(0x009AF5FC, uint32) != volume) { +#ifdef USE_MIXER + Mixer_Channel_Volume(gMusicChannels[2], DStoMixerVolume(volume)); +#else sound_channel_set_volume(2, volume);//RCT2_CALLPROC_2(0x00401AD3, int, int, 2, volume); +#endif RCT2_GLOBAL(0x009AF5FC, uint32) = volume; } } @@ -393,7 +442,7 @@ void peep_applause() } // Play applause noise - sound_play_panned(SOUND_APPLAUSE, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) / 2); + sound_play_panned(SOUND_APPLAUSE, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) / 2, 0, 0, 0); } /** @@ -447,8 +496,8 @@ void get_arguments_from_action(rct_peep* peep, uint32 *argument_1, uint32* argum break; case PEEP_STATE_WALKING: case 0x14: - if (peep->var_C5 != 0xFF){ - ride = g_ride_list[peep->var_C5]; + if (peep->guest_heading_to_ride_id != 0xFF){ + ride = g_ride_list[peep->guest_heading_to_ride_id]; *argument_1 = STR_HEADING_FOR | (ride.name << 16); *argument_2 = ride.name_arguments; } @@ -586,4 +635,137 @@ void get_arguments_from_thought(rct_peep_thought thought, uint32* argument_1, ui */ int peep_can_be_picked_up(rct_peep* peep){ return RCT2_ADDRESS(0x982004, uint8)[peep->state] & 1; -} \ No newline at end of file +} + +enum{ + PEEP_FACE_OFFSET_ANGRY = 0, + PEEP_FACE_OFFSET_VERY_VERY_SICK, + PEEP_FACE_OFFSET_VERY_SICK, + PEEP_FACE_OFFSET_SICK, + PEEP_FACE_OFFSET_VERY_TIRED, + PEEP_FACE_OFFSET_TIRED, + PEEP_FACE_OFFSET_VERY_VERY_UNHAPPY, + PEEP_FACE_OFFSET_VERY_UNHAPPY, + PEEP_FACE_OFFSET_UNHAPPY, + PEEP_FACE_OFFSET_NORMAL, + PEEP_FACE_OFFSET_HAPPY, + PEEP_FACE_OFFSET_VERY_HAPPY, + PEEP_FACE_OFFSET_VERY_VERY_HAPPY, +}; + +const int face_sprite_small[] = { + SPR_PEEP_SMALL_FACE_ANGRY, + SPR_PEEP_SMALL_FACE_VERY_VERY_SICK, + SPR_PEEP_SMALL_FACE_VERY_SICK, + SPR_PEEP_SMALL_FACE_SICK, + SPR_PEEP_SMALL_FACE_VERY_TIRED, + SPR_PEEP_SMALL_FACE_TIRED, + SPR_PEEP_SMALL_FACE_VERY_VERY_UNHAPPY, + SPR_PEEP_SMALL_FACE_VERY_UNHAPPY, + SPR_PEEP_SMALL_FACE_UNHAPPY, + SPR_PEEP_SMALL_FACE_NORMAL, + SPR_PEEP_SMALL_FACE_HAPPY, + SPR_PEEP_SMALL_FACE_VERY_HAPPY, + SPR_PEEP_SMALL_FACE_VERY_VERY_HAPPY, +}; + +const int face_sprite_large[] = { + SPR_PEEP_LARGE_FACE_ANGRY, + SPR_PEEP_LARGE_FACE_VERY_VERY_SICK, + SPR_PEEP_LARGE_FACE_VERY_SICK, + SPR_PEEP_LARGE_FACE_SICK, + SPR_PEEP_LARGE_FACE_VERY_TIRED, + SPR_PEEP_LARGE_FACE_TIRED, + SPR_PEEP_LARGE_FACE_VERY_VERY_UNHAPPY, + SPR_PEEP_LARGE_FACE_VERY_UNHAPPY, + SPR_PEEP_LARGE_FACE_UNHAPPY, + SPR_PEEP_LARGE_FACE_NORMAL, + SPR_PEEP_LARGE_FACE_HAPPY, + SPR_PEEP_LARGE_FACE_VERY_HAPPY, + SPR_PEEP_LARGE_FACE_VERY_VERY_HAPPY, +}; + +int get_face_sprite_offset(rct_peep *peep){ + + // ANGRY + if (peep->var_F3) return PEEP_FACE_OFFSET_ANGRY; + + // VERY_VERY_SICK + if (peep->nausea > 200) return PEEP_FACE_OFFSET_VERY_VERY_SICK; + + // VERY_SICK + if (peep->nausea > 170) return PEEP_FACE_OFFSET_VERY_SICK; + + // SICK + if (peep->nausea > 140) return PEEP_FACE_OFFSET_SICK; + + // VERY_TIRED + if (peep->energy < 46) return PEEP_FACE_OFFSET_VERY_TIRED; + + // TIRED + if (peep->energy < 70) return PEEP_FACE_OFFSET_TIRED; + + int offset = PEEP_FACE_OFFSET_VERY_VERY_UNHAPPY; + //There are 7 different happiness based faces + for (int i = 37; peep->happiness >= i; i += 37) + { + offset++; + } + + return offset; +} + +/** + * Function split into large and small sprite + * rct2: 0x00698721 + */ +int get_peep_face_sprite_small(rct_peep *peep){ + return face_sprite_small[get_face_sprite_offset(peep)]; +} + +/** + * Function split into large and small sprite + * rct2: 0x00698721 + */ +int get_peep_face_sprite_large(rct_peep *peep){ + return face_sprite_large[get_face_sprite_offset(peep)]; +} + +/** + * + * rct2: 0x0069A5A0 + * tests if a peep's name matches a cheat code, normally returns using a register flag + * @param index (eax) + * @param ride (esi) + */ +int peep_check_easteregg_name(int index, rct_peep *peep) +{ + char buffer[256]; + + format_string(buffer, peep->name_string_idx, &peep->id); + return _stricmp(buffer, gPeepEasterEggNames[index]) == 0; +} + +int peep_get_easteregg_name_id(rct_peep *peep) +{ + char buffer[256]; + int i; + + format_string(buffer, peep->name_string_idx, &peep->id); + + for (i = 0; i < countof(gPeepEasterEggNames); i++) + if (_stricmp(buffer, gPeepEasterEggNames[i]) == 0) + return i; + + return -1; + +} + +int peep_is_mechanic(rct_peep *peep) +{ + return ( + peep->sprite_identifier == SPRITE_IDENTIFIER_PEEP && + peep->type == PEEP_TYPE_STAFF && + peep->staff_type == STAFF_TYPE_MECHANIC + ); +} diff --git a/src/peep.h b/src/peep/peep.h similarity index 89% rename from src/peep.h rename to src/peep/peep.h index 30a34cb7bb..8642a154ff 100644 --- a/src/peep.h +++ b/src/peep/peep.h @@ -21,7 +21,7 @@ #ifndef _PEEP_H_ #define _PEEP_H_ -#include "rct2.h" +#include "../common.h" #define PEEP_MAX_THOUGHTS 5 @@ -296,10 +296,10 @@ enum PEEP_ITEM { }; typedef struct { - uint8 type; - uint8 item; - uint8 var_2; - uint8 var_3; + uint8 type; //0 + uint8 item; //1 + uint8 var_2; //2 + uint8 var_3; //3 } rct_peep_thought; typedef struct { @@ -332,7 +332,10 @@ typedef struct { uint8 pad_2C; uint8 sprite_type; // 0x2D uint8 type; // 0x2E - uint8 staff_type; // 0x2F + union{ // 0x2F + uint8 staff_type; + uint8 no_of_rides; + }; uint8 tshirt_colour; // 0x30 uint8 trousers_colour; // 0x31 uint16 var_32; @@ -342,7 +345,7 @@ typedef struct { uint8 energy; // 0x38 uint8 energy_growth_rate; // 0x39 uint8 happiness; // 0x3A - uint8 happiness_growth_rate; // 0x3B + sint8 happiness_growth_rate; // 0x3B uint8 nausea; // 0x3C uint8 nausea_growth_rate; // 0x3D uint8 hunger; // 0x3E @@ -351,7 +354,7 @@ typedef struct { uint8 pad_41[0x2]; uint8 intensity; // 0x43 uint8 nausea_tolerance; // 0x44 - uint8 var_45; + uint8 var_45; // Some sort of flags? money16 paid_on_drink; // 0x46 uint8 pad_48[0x10]; uint32 item_extra_flags; // 0x58 @@ -376,17 +379,23 @@ typedef struct { uint8 pad_77; uint8 var_78; uint8 pad_79[0x03]; - uint8 rides_been_on[32]; // 0x7C + uint8 rides_been_on[32]; // 0x7C + // 255 bit bitmap of every ride the peep has been on see + // window_peep_rides_update for how to use. uint32 id; // 0x9C money32 cash_in_pocket; // 0xA0 money32 cash_spent; // 0xA4 - uint8 var_A8; // 0xA8 - sint32 time_in_park; // 0xA9 + sint32 time_in_park; // 0xA8 + uint8 var_AC; // 0xAC uint8 var_AD; // creation/hire time? uint16 var_AE; rct_peep_thought thoughts[PEEP_MAX_THOUGHTS]; // 0xB0 uint8 var_C4; // 0xC4 - uint8 var_C5; + union // 0xC5 + { + uint8 staff_id; + uint8 guest_heading_to_ride_id; + }; uint8 var_C6; uint8 photo1_ride_ref; // 0xC7 uint32 flags; // 0xC8 @@ -404,8 +413,8 @@ typedef struct { uint8 no_of_drinks; // 0xED uint8 no_of_souvenirs; // 0xEE uint8 pad_EF; - uint8 var_F0; - uint8 var_F1; + uint8 voucher_type; // 0xF0 + uint8 voucher_arguments; // 0xF1 ride_id or string_offset_id uint8 pad_F2; uint8 var_F3; uint8 pad_F4[0x02]; @@ -417,6 +426,35 @@ typedef struct { uint32 item_standard_flags; // 0xFC } rct_peep; +enum { + EASTEREGG_PEEP_NAME_MICHAEL_SCHUMACHER, + EASTEREGG_PEEP_NAME_JACQUES_VILLENEUVE, + EASTEREGG_PEEP_NAME_DAMON_HILL, + EASTEREGG_PEEP_NAME_MR_BEAN, + EASTEREGG_PEEP_NAME_CHRIS_SAWYER, + EASTEREGG_PEEP_NAME_KATIE_BRAYSHAW, + EASTEREGG_PEEP_NAME_MELANIE_WARN, + EASTEREGG_PEEP_NAME_SIMON_FOSTER, + EASTEREGG_PEEP_NAME_JOHN_WARDLEY, + EASTEREGG_PEEP_NAME_LISA_STIRLING, + EASTEREGG_PEEP_NAME_DONALD_MACRAE, + EASTEREGG_PEEP_NAME_KATHERINE_MCGOWAN, + EASTEREGG_PEEP_NAME_FRANCES_MCGOWAN, + EASTEREGG_PEEP_NAME_CORINA_MASSOURA, + EASTEREGG_PEEP_NAME_CAROL_YOUNG, + EASTEREGG_PEEP_NAME_MIA_SHERIDAN, + EASTEREGG_PEEP_NAME_KATIE_RODGER, + EASTEREGG_PEEP_NAME_EMMA_GARRELL, + EASTEREGG_PEEP_NAME_JOANNE_BARTON, + EASTEREGG_PEEP_NAME_FELICITY_ANDERSON, + EASTEREGG_PEEP_NAME_KATIE_SMITH, + EASTEREGG_PEEP_NAME_EILIDH_BELL, + EASTEREGG_PEEP_NAME_NANCY_STILLWAGON, + EASTEREGG_PEEP_NAME_ANDY_HINE, + EASTEREGG_PEEP_NAME_ELISSA_WHITE, + EASTEREGG_PEEP_NAME_DAVID_ELLIS +}; + /** Helper macro until rides are stored in this module. */ #define GET_PEEP(sprite_index) &(g_sprite_list[sprite_index].peep) @@ -445,5 +483,10 @@ void peep_applause(); rct_peep *peep_generate(int x, int y, int z); void get_arguments_from_action(rct_peep* peep, uint32 *argument_1, uint32* argument_2); void get_arguments_from_thought(rct_peep_thought thought, uint32* argument_1, uint32* argument_2); +int get_peep_face_sprite_small(rct_peep *peep); +int get_peep_face_sprite_large(rct_peep *peep); +int peep_check_easteregg_name(int index, rct_peep *peep); +int peep_get_easteregg_name_id(rct_peep *peep); +int peep_is_mechanic(rct_peep *peep); #endif diff --git a/src/staff.c b/src/peep/staff.c similarity index 85% rename from src/staff.c rename to src/peep/staff.c index ce46f47525..4bbcf64275 100644 --- a/src/staff.c +++ b/src/peep/staff.c @@ -18,15 +18,14 @@ * along with this program. If not, see . *****************************************************************************/ -#include "staff.h" -#include "addresses.h" -#include "rct2.h" -#include "game.h" -#include "finance.h" +#include "../addresses.h" +#include "../game.h" +#include "../interface/viewport.h" +#include "../localisation/string_ids.h" +#include "../management/finance.h" +#include "../world/sprite.h" #include "peep.h" -#include "sprite.h" -#include "string_ids.h" -#include "viewport.h" +#include "staff.h" /** * @@ -99,7 +98,7 @@ void game_command_hire_new_staff_member(int* eax, int* ebx, int* ecx, int* edx, int i; for (i = 0; i < STAFF_MAX_COUNT; i++) { - if (!(RCT2_ADDRESS(0x013CA672, uint8)[i] & 1)) + if (!(RCT2_ADDRESS(RCT2_ADDRESS_STAFF_MODE_ARRAY, uint8)[i] & 1)) break; } @@ -220,9 +219,9 @@ void game_command_hire_new_staff_member(int* eax, int* ebx, int* ecx, int* edx, RCT2_CALLPROC_X(0x00699115, (uint32)ebp & 0xFFFFFF3F, 0, 0, 0, (int)newPeep, 0, (*ebp << 25) | (*ebp >> 6)); - newPeep->var_C5 = newStaffId; + newPeep->staff_id = newStaffId; - RCT2_ADDRESS(0x013CA672, uint8)[newStaffId] = 1; + RCT2_ADDRESS(RCT2_ADDRESS_STAFF_MODE_ARRAY, uint8)[newStaffId] = STAFF_MODE_WALK; for (int edi = 0; edi < 0x80; edi++) { int addr = 0x013B0E72 + (newStaffId << 9) + edi * 4; @@ -267,4 +266,27 @@ uint16 hire_new_staff_member(uint8 staff_type) return 0xFFFF; return edi; -} \ No newline at end of file +} + +void sub_6C0C3F() +{ + register rct_peep* peep; + + for (register uint8 staff_type = 0; staff_type < STAFF_TYPE_COUNT; ++staff_type) + { + for (register uint8 i = 0; i < 128; ++i) + RCT2_ADDRESS(0x13B0E72 + (staff_type + STAFF_MAX_COUNT) * 512, uint32)[i] = 0; + + for (register uint16 sprite_index = RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_START_PEEP, uint16); sprite_index != SPRITE_INDEX_NULL; sprite_index = peep->next) + { + peep = GET_PEEP(sprite_index); + + if (peep->type == PEEP_TYPE_STAFF && staff_type == peep->staff_type) + { + for (register uint8 i = 0; i < 128; ++i) + RCT2_ADDRESS(0x13B0E72 + (staff_type + STAFF_MAX_COUNT) * 512, uint32)[i] |= RCT2_ADDRESS(0x13B0E72 + (peep->staff_id * 512) * 512, uint32)[i]; + + } + } + } +} diff --git a/src/staff.h b/src/peep/staff.h similarity index 90% rename from src/staff.h rename to src/peep/staff.h index 533c0b4a8f..72e9f0c965 100644 --- a/src/staff.h +++ b/src/peep/staff.h @@ -21,9 +21,16 @@ #ifndef _STAFF_H_ #define _STAFF_H_ -#include "rct2.h" +#include "../common.h" #define STAFF_MAX_COUNT 0xC8 +#define STAFF_TYPE_COUNT 0x04 + +enum STAFF_MODE { + STAFF_MODE_NONE, + STAFF_MODE_WALK, + STAFF_MODE_PATROL = 3 +}; enum STAFF_TYPE { STAFF_TYPE_HANDYMAN, @@ -37,5 +44,6 @@ void game_command_hire_new_staff_member(int* eax, int* ebx, int* ecx, int* edx, void update_staff_colour(uint8 staff_type, uint16 color); uint16 hire_new_staff_member(uint8 staff_type); +void sub_6C0C3F(); #endif \ No newline at end of file diff --git a/src/osinterface.c b/src/platform/osinterface.c similarity index 94% rename from src/osinterface.c rename to src/platform/osinterface.c index 017fa8c551..ed0090b4d4 100644 --- a/src/osinterface.c +++ b/src/platform/osinterface.c @@ -25,15 +25,14 @@ #include #include -#include "addresses.h" -#include "config.h" -#include "gfx.h" -#include "input.h" +#include "../addresses.h" +#include "../config.h" +#include "../cursors.h" +#include "../drawing/drawing.h" +#include "../input.h" +#include "../interface/screenshot.h" +#include "../interface/window.h" #include "osinterface.h" -#include "screenshot.h" -#include "window.h" -#include "rct2.h" -#include "cursors.h" typedef void(*update_palette_func)(char*, int, int); @@ -57,6 +56,9 @@ static SDL_Cursor* _cursors[NO_CURSORS]; static const int _fullscreen_modes[] = { 0, SDL_WINDOW_FULLSCREEN, SDL_WINDOW_FULLSCREEN_DESKTOP }; +static unsigned int _lastGestureTimestamp; +static float _gestureRadius; + void osinterface_init() { osinterface_create_window(); @@ -67,6 +69,17 @@ void osinterface_init() // RCT2_CALLPROC(0x00404584); // dinput_init() } +int osinterface_scancode_to_rct_keycode(int sdl_key){ + char keycode = (char)SDL_GetKeyFromScancode((SDL_Scancode)sdl_key); + + // Until we reshufle the text files to use the new positions + // this will suffice to move the majority to the correct positions. + // Note any special buttons PgUp PgDwn are mapped wrong. + if (keycode >= 'a' && keycode <= 'z')keycode = toupper(keycode); + + return keycode; +} + /** * This is not quite the same as the below function as we don't want to * derfererence the cursor before the function. @@ -395,6 +408,25 @@ void osinterface_process_messages() screenshot_check(); } break; + case SDL_MULTIGESTURE: + if (e.mgesture.numFingers == 2) { + if (e.mgesture.timestamp > _lastGestureTimestamp + 1000) + _gestureRadius = 0; + _lastGestureTimestamp = e.mgesture.timestamp; + _gestureRadius += e.mgesture.dDist; + + // Zoom gesture + const int tolerance = 128; + int gesturePixels = (int)(_gestureRadius * RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16)); + if (gesturePixels > tolerance) { + _gestureRadius = 0; + handle_shortcut_command(SHORTCUT_ZOOM_VIEW_IN); + } else if (gesturePixels < -tolerance) { + _gestureRadius = 0; + handle_shortcut_command(SHORTCUT_ZOOM_VIEW_OUT); + } + } + break; default: break; } @@ -654,7 +686,7 @@ int osinterface_file_close(HANDLE handle) * * rct2: 0x00408060 */ -HANDLE osinterface_file_open(char* filename) +HANDLE osinterface_file_open(const char* filename) { return CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS | FILE_ATTRIBUTE_NORMAL, 0); } @@ -663,7 +695,7 @@ HANDLE osinterface_file_open(char* filename) * * rct2: 0x0040807D */ -HANDLE osinterface_file_create(char* filename) +HANDLE osinterface_file_create(const char* filename) { return CreateFileA(filename, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); } @@ -672,7 +704,7 @@ HANDLE osinterface_file_create(char* filename) * * rct2: 0x00408099 */ -int osinterface_file_move(char* srcfilename, char* dstfilename) +int osinterface_file_move(const char* srcfilename, const char* dstfilename) { return (MoveFileA(srcfilename, dstfilename) != 0) - 1; } @@ -681,7 +713,7 @@ int osinterface_file_move(char* srcfilename, char* dstfilename) * * rct2: 0x004080AF */ -int osinterface_file_delete(char* filename) +int osinterface_file_delete(const char* filename) { return (DeleteFileA(filename) != 0) - 1; } diff --git a/src/osinterface.h b/src/platform/osinterface.h similarity index 91% rename from src/osinterface.h rename to src/platform/osinterface.h index a9480bb0db..d88eead8bc 100644 --- a/src/osinterface.h +++ b/src/platform/osinterface.h @@ -21,7 +21,8 @@ #ifndef _SDL_INTERFACE_H_ #define _SDL_INTERFACE_H_ -#include "rct2.h" +#include +#include "../common.h" enum { CURSOR_UP = 0, @@ -74,7 +75,7 @@ typedef struct { char path[260]; uint32 var_20C; uint8 pad_210[0x100]; - char addon[15][0x80]; + char addon[16][0x80]; uint32 addons; //0xB10 } rct2_install_info; @@ -96,6 +97,10 @@ void osinterface_progressbar_setpos(int pos); void osinterface_set_cursor(char cursor); +HANDLE osinterface_file_open(const char* filename); +int osinterface_file_read(HANDLE handle, void* data, int size); +int osinterface_file_close(HANDLE handle); + int osinterface_open_common_file_dialog(int type, char *title, char *filename, char *filterPattern, char *filterName); void osinterface_show_messagebox(char* message); char* osinterface_open_directory_browser(char *title); @@ -107,5 +112,6 @@ int osinterface_directory_exists(const char *path); int osinterface_ensure_directory_exists(const char *path); char osinterface_get_path_separator(); +int osinterface_scancode_to_rct_keycode(int sdl_key); #endif diff --git a/src/platform/osx.c b/src/platform/osx.c new file mode 100644 index 0000000000..d16040f99d --- /dev/null +++ b/src/platform/osx.c @@ -0,0 +1,36 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of OpenRCT2. + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#ifdef __APPLE__ + +/** + * OSX entry point to OpenRCT2. + */ +// int main(char *argv[], int argc) +// { +// return 0; +// } + +char platform_get_path_separator() +{ + return '/'; +} + +#endif \ No newline at end of file diff --git a/src/platform/platform.h b/src/platform/platform.h new file mode 100644 index 0000000000..88678c3ec8 --- /dev/null +++ b/src/platform/platform.h @@ -0,0 +1,30 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of OpenRCT2. + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#ifndef _PLATFORM_H_ +#define _PLATFORM_H_ + + +// Platform specific definitions +char platform_get_path_separator(); +int platform_directory_exists(const char *path); +int platform_ensure_directory_exists(const char *path); + +#endif \ No newline at end of file diff --git a/src/platform/shared.c b/src/platform/shared.c new file mode 100644 index 0000000000..20a00a3bd2 --- /dev/null +++ b/src/platform/shared.c @@ -0,0 +1,20 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of OpenRCT2. + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + diff --git a/src/platform/unix.c b/src/platform/unix.c new file mode 100644 index 0000000000..47aecde2d2 --- /dev/null +++ b/src/platform/unix.c @@ -0,0 +1,38 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of OpenRCT2. + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#ifndef _WIN32 +#ifndef __APPLE__ + +/** + * Unix, linux and fallback entry point to OpenRCT2. + */ +// int main(char *argv[], int argc) +// { +// return 0; +// } + +char platform_get_path_separator() +{ + return '/'; +} + +#endif +#endif \ No newline at end of file diff --git a/src/platform/windows.c b/src/platform/windows.c new file mode 100644 index 0000000000..1d683f9e8b --- /dev/null +++ b/src/platform/windows.c @@ -0,0 +1,76 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of OpenRCT2. + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#ifdef _WIN32 + +#include + +/** + * Windows entry point to OpenRCT2 without a console window. + */ +// int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) +// { +// return 0; +// } + +/** + * Windows entry point to OpenRCT2 with a console window using a traditional C main function. + */ +// int main(char *argv[], int argc) +// { +// return 0; +// } + +/** + * Entry point for when the DLL is loaded. This will be removed when OpenRCT2 can be built as a stand alone application. + */ +BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved) +{ + return TRUE; +} + +/** + * The function that is called directly from the host application (rct2.exe)'s WinMain. This will be removed when OpenRCT2 can + * be built as a stand alone application. + */ +// __declspec(dllexport) int StartOpenRCT(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) +// { +// } + +char platform_get_path_separator() +{ + return '\\'; +} + +int platform_directory_exists(const char *path) +{ + DWORD dwAttrib = GetFileAttributes(path); + return dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY); +} + +int platform_ensure_directory_exists(const char *path) +{ + if (platform_directory_exists(path)) + return 1; + + return CreateDirectory(path, NULL); +} + +#endif \ No newline at end of file diff --git a/src/rct2.c b/src/rct2.c index 98c82e7bfd..9e6a05190b 100644 --- a/src/rct2.c +++ b/src/rct2.c @@ -29,28 +29,27 @@ #include #include #include "addresses.h" -#include "audio.h" -#include "climate.h" +#include "audio/audio.h" +#include "audio/mixer.h" #include "config.h" -#include "date.h" +#include "drawing/drawing.h" #include "editor.h" #include "game.h" -#include "gfx.h" +#include "interface/viewport.h" #include "intro.h" -#include "language.h" -#include "map.h" -#include "news_item.h" +#include "localisation/date.h" +#include "localisation/localisation.h" +#include "management/news_item.h" #include "object.h" -#include "osinterface.h" -#include "park.h" -#include "rct2.h" -#include "ride.h" +#include "platform/osinterface.h" +#include "ride/ride.h" +#include "ride/track.h" #include "scenario.h" #include "title.h" -#include "track.h" -#include "viewport.h" -#include "sprite.h" -#include "string_ids.h" +#include "world/map.h" +#include "world/park.h" +#include "world/climate.h" +#include "world/sprite.h" typedef struct tm tm_t; @@ -70,11 +69,6 @@ PCHAR *CommandLineToArgvA(PCHAR CmdLine, int *_argc); static int _finished; static jmp_buf _end_update_jump; -BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved) -{ - return TRUE; -} - __declspec(dllexport) int StartOpenRCT(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { print_launch_information(); @@ -90,6 +84,7 @@ __declspec(dllexport) int StartOpenRCT(HINSTANCE hInstance, HINSTANCE hPrevInsta config_init(); language_open(gGeneral_config.language); rct2_init(); + Mixer_Init(NULL); rct2_loop(); osinterface_free(); exit(0); @@ -161,13 +156,16 @@ void rct2_init() // RCT2_CALLPROC_EBPSAFE(0x00674B81); // pointless expansion pack crap object_list_load(); scenario_load_list(); - track_load_list(253); + + ride_list_item item = { 253, 0 }; + track_load_list(item); + gfx_load_g1(); //RCT2_CALLPROC_EBPSAFE(0x006C19AC); //Load character widths gfx_load_character_widths(); osinterface_init(); - RCT2_CALLPROC_EBPSAFE(0x006BA8E0); // init_audio(); + audio_init1();//RCT2_CALLPROC_EBPSAFE(0x006BA8E0); // init_audio(); viewport_init_all(); news_item_init_queue(); get_local_time(); @@ -185,7 +183,7 @@ void rct2_init() RCT2_CALLPROC_EBPSAFE(0x006DFEE4); window_new_ride_init_vars(); window_guest_list_init_vars_b(); - window_staff_init_vars(); + window_staff_list_init_vars(); title_load(); @@ -683,4 +681,4 @@ PCHAR *CommandLineToArgvA(PCHAR CmdLine, int *_argc) (*_argc) = argc; return argv; -} \ No newline at end of file +} diff --git a/src/rct2.h b/src/rct2.h index 643aec1c29..51f982c4ed 100644 --- a/src/rct2.h +++ b/src/rct2.h @@ -84,13 +84,15 @@ typedef fixed32_1dp money32; // would write FIXED_2DP(3,65) #define FIXED_XDP(x, whole, fraction) ((whole) * (10 * x) + (fraction)) #define FIXED_1DP(whole, fraction) FIXED_XDP(1, whole, fraction) -#define FIXED_2DP(whole, fraction) FIXED_XDP(2, whole, fraction) +#define FIXED_2DP(whole, fraction) FIXED_XDP(10, whole, fraction) // Construct a money value in the format MONEY(10,70) to represent 10.70. Fractional part must be two digits. #define MONEY(whole, fraction) ((whole) * 10 + ((fraction) / 10)) #define MONEY32_UNDEFINED ((money32)0x80000000) +typedef unsigned short rct_string_id; + void rct2_finish(); enum { diff --git a/src/readme.md b/src/readme.md new file mode 100644 index 0000000000..f354d9e6fb --- /dev/null +++ b/src/readme.md @@ -0,0 +1,45 @@ +# Source directory structure + +- **audio** + + Contains files for mixing and playing music and sound. + +- **drawing** + + Low level drawing logic and palette tables. + +- **interface** + + Window and widget logic, includes high level drawing and input. + +- **localisation** + + String IDs, currency and date logic. + +- **network** + + Network and multiplayer logic, includes management of network games and downloading / uploading of content. + +- **management** + + Park management logic such as finance, marketing and research. + +- **platform** + + Compiler and operating system specific code such as type definitions, message handling and file input / output. + +- **ride** + + Data and logic for rides, vehicles and track. + +- **util** + + Utility and helper functions. + +- **windows** + + Definitions and logic for all the windows in the game. + +- **world** + + World objects and mechanics such as the climate, landscape, sprites and park. \ No newline at end of file diff --git a/src/ride.c b/src/ride/ride.c similarity index 59% rename from src/ride.c rename to src/ride/ride.c index 7478d4cccc..e7931aee4b 100644 --- a/src/ride.c +++ b/src/ride/ride.c @@ -19,15 +19,18 @@ *****************************************************************************/ #include -#include "addresses.h" -#include "game.h" -#include "map.h" -#include "news_item.h" -#include "sprite.h" +#include "../addresses.h" +#include "../game.h" +#include "../interface/window.h" +#include "../localisation/localisation.h" +#include "../management/news_item.h" +#include "../peep/peep.h" +#include "../peep/staff.h" +#include "../scenario.h" +#include "../world/map.h" +#include "../world/sprite.h" #include "ride.h" -#include "sprite.h" -#include "peep.h" -#include "window.h" +#include "ride_data.h" #pragma region Ride classification table @@ -152,7 +155,7 @@ void ride_init_all() for (i = 0; i < MAX_RIDE_MEASUREMENTS; i++) { ride_measurement = GET_RIDE_MEASUREMENT(i); - ride_measurement->var_00 = 0xFF; + ride_measurement->ride_index = 255; } } @@ -427,10 +430,10 @@ rct_map_element *ride_find_track_gap(rct_map_element *startTrackElement, int *ou * * rct2: 0x006B4800 */ -void ride_construct_new(int list_item) +void ride_construct_new(ride_list_item listItem) { int eax, ebx, ecx, edx, esi, edi, ebp; - edx = list_item; + edx = *((uint16*)&listItem); eax = 0; ecx = 0; ebx = 1; @@ -474,3 +477,370 @@ int ride_try_construct(rct_map_element *trackMapElement) RCT2_CALLPROC_X(0x006CC056, 0, 0, 0, (int)trackMapElement, 0, 0, 0); return 1; } + +/** + * + * rct2: 0x006AF561 + */ +void ride_get_status(int rideIndex, int *formatSecondary, int *argument) +{ + rct_ride *ride = &g_ride_list[rideIndex]; + + if (ride->lifecycle_flags & RIDE_LIFECYCLE_CRASHED) { + *formatSecondary = STR_CRASHED; + return; + } + if (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN) { + *formatSecondary = STR_BROKEN_DOWN; + return; + } + if (ride->status == RIDE_STATUS_CLOSED) { + *formatSecondary = STR_CLOSED; + return; + } + if (ride->status == RIDE_STATUS_TESTING) { + *formatSecondary = STR_TEST_RUN; + return; + } + rct_peep *peep = GET_PEEP(ride->race_winner); + if (ride->mode == RIDE_MODE_RACE && !(ride->lifecycle_flags & RIDE_LIFECYCLE_PASS_STATION_NO_STOPPING) && ride->race_winner != 0xFFFF && peep->sprite_identifier == SPRITE_IDENTIFIER_PEEP) { + if (peep->name_string_idx == STR_GUEST) { + *argument = peep->id; + *formatSecondary = STR_RACE_WON_BY_GUEST; + } else { + *argument = peep->name_string_idx; + *formatSecondary = STR_RACE_WON_BY; + } + } else { + if (!(RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + ride->type * 8, uint32) & 0x20000)) { + *argument = ride->num_riders; + *formatSecondary = STR_PERSON_ON_RIDE; + if(*argument != 1) + *formatSecondary = STR_PEOPLE_ON_RIDE; + + } else { + *formatSecondary = STR_OPEN; + } + } +} + +rct_peep *ride_get_assigned_mechanic(rct_ride *ride) +{ + rct_peep *peep; + + if (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN) { + if ( + ride->mechanic_status == RIDE_MECHANIC_STATUS_HEADING || + ride->mechanic_status == 3 || + ride->mechanic_status == 4 + ) { + peep = &(g_sprite_list[ride->mechanic].peep); + if (peep_is_mechanic(peep)) + return peep; + } + } + + return NULL; +} + +int ride_get_total_length(rct_ride *ride) +{ + int i, totalLength = 0; + for (i = 0; i < ride->num_stations; i++) + totalLength += ride->length[i]; + return totalLength; +} + +int ride_can_have_multiple_circuits(rct_ride *ride) +{ + if (!(RCT2_GLOBAL(0x0097D4F2 + (ride->type * 8), uint16) & 0x200)) + return 0; + + // Only allow circuit or launch modes + if ( + ride->mode != RIDE_MODE_CONTINUOUS_CIRCUIT && + ride->mode != RIDE_MODE_REVERSE_INCLINE_LAUNCHED_SHUTTLE && + ride->mode != RIDE_MODE_POWERED_LAUNCH + ) { + return 0; + } + + // Must have no more than one vehicle and one station + if (ride->num_vehicles > 1 || ride->num_stations > 1) + return 0; + + return 1; +} + +track_colour ride_get_track_colour(rct_ride *ride, int colourScheme) +{ + track_colour result; + result.main = ride->track_colour_main[colourScheme]; + result.additional = ride->track_colour_additional[colourScheme]; + result.supports = ride->track_colour_supports[colourScheme]; + return result; +} + +vehicle_colour ride_get_vehicle_colour(rct_ride *ride, int vehicleIndex) +{ + vehicle_colour result; + result.main = ride->vehicle_colours[vehicleIndex] & 0xFF; + result.additional_1 = ride->vehicle_colours[vehicleIndex] >> 8; + result.additional_2 = ride->vehicle_colours_extended[vehicleIndex]; + return result; +} + +/** + * + * rct2: 0x006AC988 + * set the speed of the go kart type vehicle at the start to a random value or alter if peep name is an easter egg + * @param ride (esi) + */ +void ride_init_vehicle_speed(rct_ride *ride) +{ + rct_ride_type *rideEntry; + rct_vehicle *vehicle; + uint8 *unk; + int i; + + for (i = 0; i < ride->num_vehicles; i++) { + vehicle = &g_sprite_list[ride->vehicles[i]].vehicle; + vehicle->var_48 &= ~(1 << 6); + + rideEntry = GET_RIDE_ENTRY(vehicle->var_D6); + unk = (uint8*)((int)rideEntry + (vehicle->var_31 * 0x65)); + + vehicle->speed = (scenario_rand() & 16) - 8 + RCT2_GLOBAL(unk + 0x76, uint8); + + if (vehicle->var_B3) { + rct_peep *peep = &g_sprite_list[vehicle->peep].peep; + + switch (peep_get_easteregg_name_id(peep)) { + case EASTEREGG_PEEP_NAME_MICHAEL_SCHUMACHER: + vehicle->speed += 35; + break; + case EASTEREGG_PEEP_NAME_JACQUES_VILLENEUVE: + vehicle->speed += 25; + break; + case EASTEREGG_PEEP_NAME_DAMON_HILL: + vehicle->speed += 55; + break; + case EASTEREGG_PEEP_NAME_CHRIS_SAWYER: + vehicle->speed += 14; + break; + case EASTEREGG_PEEP_NAME_MR_BEAN: + vehicle->speed = 9; + break; + } + } + } +} + +rct_ride_type *ride_get_entry(rct_ride *ride) +{ + return GET_RIDE_ENTRY(ride->subtype); +} + +uint8 *get_ride_entry_indices_for_ride_type(uint8 rideType) +{ + uint8 *typeToRideEntryIndexMap = (uint8*)0x009E32F8; + uint8 *entryIndexList = typeToRideEntryIndexMap; + while (rideType > 0) { + do { + entryIndexList++; + } while (*(entryIndexList - 1) != 255); + rideType--; + } + return entryIndexList; +} + + + +/** + * rct2: 0x006B64F2 + */ +void ride_measurement_update(rct_ride_measurement *measurement) +{ + uint16 spriteIndex; + rct_ride *ride; + rct_vehicle *vehicle; + int unk, velocity, altitude, verticalG, lateralG; + + ride = GET_RIDE(measurement->ride_index); + spriteIndex = ride->vehicles[measurement->vehicle_index]; + if (spriteIndex == SPRITE_INDEX_NULL) + return; + + vehicle = &(g_sprite_list[spriteIndex].vehicle); + + if (measurement->flags & RIDE_MEASUREMENT_FLAG_UNLOADING) { + if (vehicle->status != VEHICLE_STATUS_DEPARTING && vehicle->status != VEHICLE_STATUS_STOPPING) + return; + + measurement->flags &= ~RIDE_MEASUREMENT_FLAG_UNLOADING; + if (measurement->var_0B == vehicle->var_4B) + measurement->current_item = 0; + } + + if (vehicle->status == VEHICLE_STATUS_UNLOADING_PASSENGERS) { + measurement->flags |= RIDE_MEASUREMENT_FLAG_UNLOADING; + return; + } + + unk = (vehicle->var_36 / 4) & 0xFF; + if (unk == 216 || unk == 123 || unk == 9 || unk == 63 || unk == 147 || unk == 155) + if (vehicle->velocity == 0) + return; + + if (measurement->current_item >= RIDE_MEASUREMENT_MAX_ITEMS) + return; + + if (measurement->flags & RIDE_MEASUREMENT_FLAG_G_FORCES) { + vehicle_get_g_forces(vehicle, &verticalG, &lateralG); + verticalG = clamp(-127, verticalG / 8, 127); + lateralG = clamp(-127, lateralG / 8, 127); + + if (RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, uint32) & 1) { + verticalG = (verticalG + measurement->vertical[measurement->current_item]) / 2; + lateralG = (lateralG + measurement->lateral[measurement->current_item]) / 2; + } + + measurement->vertical[measurement->current_item] = verticalG & 0xFF; + measurement->lateral[measurement->current_item] = lateralG & 0xFF; + } + + velocity = min(abs((vehicle->velocity * 5) >> 16), 255); + altitude = min(vehicle->z / 8, 255); + + if (RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, uint32) & 1) { + velocity = (velocity + measurement->velocity[measurement->current_item]) / 2; + altitude = (altitude + measurement->altitude[measurement->current_item]) / 2; + } + + measurement->velocity[measurement->current_item] = velocity & 0xFF; + measurement->altitude[measurement->current_item] = altitude & 0xFF; + + if (RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, uint32) & 1) { + measurement->current_item++; + measurement->num_items = max(measurement->num_items, measurement->current_item); + } +} + +/** + * rct2: 0x006B6456 + */ +void ride_measurements_update() +{ + rct_ride *ride; + rct_ride_measurement *measurement; + rct_vehicle *vehicle; + int i, j; + uint16 spriteIndex; + + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) + return; + + // For each ride measurement + for (i = 0; i < MAX_RIDE_MEASUREMENTS; i++) { + measurement = GET_RIDE_MEASUREMENT(i); + if (measurement->ride_index == 255) + continue; + + ride = GET_RIDE(measurement->ride_index); + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK)) + continue; + + if (measurement->flags & RIDE_MEASUREMENT_FLAG_RUNNING) { + ride_measurement_update(measurement); + } else { + // For each vehicle + for (j = 0; j < ride->num_vehicles; j++) { + spriteIndex = ride->vehicles[j]; + if (spriteIndex == SPRITE_INDEX_NULL) + continue; + + vehicle = &(g_sprite_list[spriteIndex].vehicle); + if (vehicle->status == VEHICLE_STATUS_DEPARTING || vehicle->status == VEHICLE_STATUS_STOPPING) { + measurement->vehicle_index = j; + measurement->var_0B = vehicle->var_4B; + measurement->flags |= RIDE_MEASUREMENT_FLAG_RUNNING; + measurement->flags &= ~RIDE_MEASUREMENT_FLAG_UNLOADING; + ride_measurement_update(measurement); + break; + } + } + + } + } +} + +/** + * + * rct2: 0x006B66D9 + */ +rct_ride_measurement *ride_get_measurement(int rideIndex, rct_string_id *message) +{ + rct_ride *ride; + rct_ride_measurement *measurement; + uint32 lruTicks; + int i, lruIndex; + + ride = GET_RIDE(rideIndex); + + // Check if ride type supports data logging + if (!(RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x200)) { + if (message != NULL) *message = STR_DATA_LOGGING_NOT_AVAILABLE_FOR_THIS_TYPE_OF_RIDE; + return NULL; + } + + // Check if a measurement already exists for this ride + for (i = 0; i < MAX_RIDE_MEASUREMENTS; i++) { + measurement = GET_RIDE_MEASUREMENT(i); + if (measurement->ride_index == i) + goto use_measurement; + } + + // Find a free measurement + for (i = 0; i < MAX_RIDE_MEASUREMENTS; i++) { + measurement = GET_RIDE_MEASUREMENT(i); + if (measurement->ride_index == 255) + goto new_measurement; + } + + // Use last recently used measurement for some other ride + lruIndex = 0; + lruTicks = 0xFFFFFFFF; + for (i = 0; i < MAX_RIDE_MEASUREMENTS; i++) { + measurement = GET_RIDE_MEASUREMENT(i); + + if (measurement->last_use_tick <= lruTicks) { + lruTicks = measurement->last_use_tick; + lruIndex = i; + } + } + + i = lruIndex; + measurement = GET_RIDE_MEASUREMENT(i); + ride->measurement_index = 255; + +new_measurement: + measurement->ride_index = rideIndex; + ride->measurement_index = i; + measurement->flags = 0; + if (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x80) + measurement->flags |= RIDE_MEASUREMENT_FLAG_G_FORCES; + measurement->num_items = 0; + measurement->current_item = 0; + +use_measurement: + measurement->last_use_tick = RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, uint32); + if (measurement->flags & 1) { + if (message != NULL) *message = 0; + return measurement; + } else { + RCT2_GLOBAL(0x013CE952, uint16) = RideNameConvention[ride->type].vehicle_name; + RCT2_GLOBAL(0x013CE952 + 2, uint16) = RideNameConvention[ride->type].station_name; + if (message != NULL) *message = STR_DATA_LOGGING_WILL_START_WHEN_NEXT_LEAVES; + return NULL; + } +} \ No newline at end of file diff --git a/src/ride.h b/src/ride/ride.h similarity index 58% rename from src/ride.h rename to src/ride/ride.h index d454020c92..8a93ddf57b 100644 --- a/src/ride.h +++ b/src/ride/ride.h @@ -21,9 +21,9 @@ #ifndef _RIDE_H_ #define _RIDE_H_ -#include "map.h" -#include "rct2.h" -#include "string_ids.h" +#include "../common.h" +#include "../peep/peep.h" +#include "../world/map.h" typedef fixed16_2dp ride_rating; @@ -38,6 +38,14 @@ typedef struct { ride_rating nausea; } rating_tuple; +/** + * Couples a ride type and subtype together. + */ +typedef struct { + uint8 type; + uint8 entry_index; +} ride_list_item; + /** * Ride type structure. * size: unknown @@ -49,15 +57,22 @@ typedef struct { uint32 var_008; uint8 var_00C; uint8 var_00D; - uint8 pad_00E[0x5]; + uint8 var_00E; + uint8 var_00F; + uint8 var_010; + uint8 var_011; + uint8 var_012; uint8 var_013; uint8 pad_014[0x19E]; sint8 excitement_multipler; // 0x1B2 sint8 intensity_multipler; // 0x1B3 sint8 nausea_multipler; // 0x1B4 - uint8 pad_1B5[0x09]; + uint8 pad_1B5; + uint32 var_1B6; + uint8 pad_1BA[0x04]; uint8 category[2]; // 0x1BE uint8 shop_item; // 0x1C0 + uint8 shop_item_secondary; // 0x1C1 } rct_ride_type; /** @@ -72,7 +87,7 @@ typedef struct { uint16 pad_002; uint8 mode; // 0x004 uint8 colour_scheme_type; // 0x005 - uint16 car_colours[32]; // 0x006 + uint16 vehicle_colours[32]; // 0x006 uint8 pad_046[0x03]; // 0 = closed, 1 = open, 2 = test uint8 status; // 0x049 @@ -81,29 +96,43 @@ typedef struct { uint16 overall_view; // 0x050 00XX = X, XX00 = Y (* 32 + 16) uint16 station_starts[4]; // 0x052 uint8 station_heights[4]; // 0x05A - uint8 pad_05E[0xC]; + uint8 pad_05E[0x4]; + uint8 var_062[4]; + uint8 pad_066[0x4]; uint16 entrances[4]; // 0x06A uint16 exits[4]; // 0x072 uint8 pad_07A[0x0C]; - uint16 train_car_map[1]; // 0x086 Points to the first car in the train - uint8 pad_088[0x3F]; + uint16 vehicles[32]; // 0x086 Points to the first car in the train + uint8 depart_flags; // 0x0C6 // Not sure if these should be uint or sint. - uint8 var_0C7; - uint8 var_0C8; - uint8 var_0C9; - - uint8 pad_0CA[0x1A]; - - sint32 var_0E4; - sint32 var_0E8; - sint32 var_0EC; - sint32 var_0F0; - uint8 pad_0F4[0x20]; - uint8 var_114; - // Track length? Number of track segments? - uint8 var_115; - uint8 pad_116[0x0E]; + uint8 num_stations; // 0x0C7 + uint8 num_vehicles; // 0x0C8 + uint8 num_cars_per_train; // 0x0C9 + uint8 pad_0CA[0x2]; + uint8 var_0CC; + uint8 var_0CD; + uint8 min_waiting_time; // 0x0CE + uint8 max_waiting_time; // 0x0CF + uint8 var_0D0; + uint8 pad_0D1[0x3]; + uint8 measurement_index; // 0x0D4 + uint8 pad_0D5[0x3]; + sint32 max_speed; // 0x0D8 + sint32 average_speed; // 0x0DC + uint8 pad_0E0[0x4]; + sint32 length[4]; // 0x0E4 + uint16 time[4]; // 0x0F4 + fixed16_2dp max_positive_vertical_g; // 0x0FC + fixed16_2dp max_negative_vertical_g; // 0x0FE + fixed16_2dp max_lateral_g; // 0x100 + uint8 pad_102[0x12]; + uint8 inversions; // 0x114 (???X XXXX) holes for mini golf + uint8 drops; // 0x115 (??XX XXXX) + uint8 pad_116; + uint8 highest_drop_height; // 0x117 + uint32 var_118; + uint8 pad_11C[0x08]; sint16 var_124; sint16 var_126; sint16 var_128; @@ -116,59 +145,82 @@ typedef struct { sint16 var_136; money16 price; // 0x138 uint8 pad_13A[0x06]; - sint16 excitement; // 0x140 - sint16 intensity; // 0x142 - uint16 nausea; // 0x144 + ride_rating excitement; // 0x140 + ride_rating intensity; // 0x142 + ride_rating nausea; // 0x144 uint16 reliability; // 0x146 uint16 pad_148; uint16 var_14A; uint8 pad_14C; uint8 var_14D; - uint8 pad_14E[0x06]; - uint32 var_154; + uint8 pad_14E[0x02]; + uint32 total_customers; // 0x150 + money32 total_profit; // 0x154 uint16 var_158; uint8 pad_15A; uint8 num_riders; // 0x15B uint8 pad_15C[0x24]; - uint16 build_date; - sint16 upkeep_cost; // 0x182 + sint16 build_date; // 0x180 + money16 upkeep_cost; // 0x182 uint16 race_winner; // 0x184 uint8 pad_186[0x06]; uint8 var_18C; - uint8 pad_18D[0x09]; + uint8 mechanic_status; // 0x18D + uint16 mechanic; // 0x18E + uint8 pad_190[0x03]; + uint8 breakdown_reason; // 0x193 + money16 price_secondary; // 0x194 uint16 var_196; // used in computing excitement, nausea, etc uint8 var_198; uint8 var_199; - uint8 pad_19A[0x14]; + uint8 inspection_interval; // 0x19A + uint8 last_inspection; // 0x19B + uint8 pad_19C[0x8]; + uint32 var_1A4; + uint8 pad_1A8[6]; uint8 var_1AE; - uint8 connected_message_throttle; - uint32 pad_1B0; - sint32 profit; // 0x1B4 + uint8 connected_message_throttle; // 0x1AF + money32 income_per_hour; // 0x1B0 + money32 profit; // 0x1B4 uint8 queue_time[4]; // 0x1B8 - uint8 var_1BC; - uint8 pad_1BD[0x10]; - uint8 var_1CD; + uint8 track_colour_main[4]; // 0x1BC + uint8 track_colour_additional[4]; // 0x1C0 + uint8 track_colour_supports[4]; // 0x1C4 + uint8 music; // 0x1C8 + uint8 entrance_style; // 0x1C9 + uint16 var_1CA; + uint8 num_block_brakes; // 0x1CC + uint8 lift_hill_speed; // 0x1CD uint16 guests_favourite; // 0x1CE uint32 lifecycle_flags; // 0x1D0 - uint8 var_1D4; - uint8 pad_1D5[0x1F]; - // Example value for wild mouse ride is d5 (before it's been constructed) - // I tried searching the IDA file for "1F4" but couldn't find places where - // this is written to. - uint16 var_1F4; - uint8 pad_1F6[0x0a]; + uint8 vehicle_colours_extended[32]; // 0x1D4 + uint16 total_air_time; // 0x1F4 + uint8 pad_1F6; + uint8 num_circuits; // 0x1F7 + uint8 pad_1F8[0x8]; uint16 queue_length[4]; // 0x200 uint8 pad_208[0x58]; } rct_ride; +#define RIDE_MEASUREMENT_MAX_ITEMS 4800 + /** * Ride measurement structure. * size: 0x04B0C */ typedef struct { - uint8 var_00; - uint8 pad_01[0x4B0B]; + uint8 ride_index; // 0x0000 + uint8 flags; // 0x0001 + uint32 last_use_tick; // 0x0002 + uint16 num_items; // 0x0006 + uint16 current_item; // 0x0008 + uint8 vehicle_index; // 0x000A + uint8 var_0B; + sint8 vertical[RIDE_MEASUREMENT_MAX_ITEMS]; // 0x000C + sint8 lateral[RIDE_MEASUREMENT_MAX_ITEMS]; // 0x12CC + uint8 velocity[RIDE_MEASUREMENT_MAX_ITEMS]; // 0x258C + uint8 altitude[RIDE_MEASUREMENT_MAX_ITEMS]; // 0x384C } rct_ride_measurement; enum { @@ -179,7 +231,7 @@ enum { // Constants used by the lifecycle_flags property at 0x1D0 enum { - RIDE_LIFECYCLE_ON_TRACK = 1, + RIDE_LIFECYCLE_ON_TRACK = 1 << 0, RIDE_LIFECYCLE_TESTED = 1 << 1, RIDE_LIFECYCLE_TEST_IN_PROGRESS = 1 << 2, RIDE_LIFECYCLE_NO_RAW_STATS = 1 << 3, @@ -189,13 +241,14 @@ enum { RIDE_LIFECYCLE_BROKEN_DOWN = 1 << 7, RIDE_LIFECYCLE_CRASHED = 1 << 10, - + RIDE_LIFECYCLE_11 = 1 << 11, RIDE_LIFECYCLE_EVER_BEEN_OPENED = 1 << 12, RIDE_LIFECYCLE_MUSIC = 1 << 13, RIDE_LIFECYCLE_INDESTRUCTIBLE = 1 << 14, RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK = 1 << 15, - RIDE_LIFECYCLE_CABLE_LIFT = 1 << 17 + RIDE_LIFECYCLE_CABLE_LIFT = 1 << 17, + RIDE_LIFECYCLE_19 = 1 << 19 }; enum { @@ -300,9 +353,9 @@ enum { }; enum { - RIDE_MODE_NORMAL = 0, + RIDE_MODE_NORMAL, RIDE_MODE_CONTINUOUS_CIRCUIT, - RIDE_MODE_REVERSE_INCLINED_SHUTTLE, + RIDE_MODE_REVERSE_INCLINE_LAUNCHED_SHUTTLE, RIDE_MODE_POWERED_LAUNCH, // RCT1 style? RIDE_MODE_SHUTTLE, RIDE_MODE_BOAT_HIRE, @@ -323,7 +376,7 @@ enum { RIDE_MODE_3D_FILM_MOUSE_TAILS, RIDE_MODE_SPACE_RINGS, RIDE_MODE_BEGINNERS, - RIDE_MODE_LIM_POWERED_LAUNCH, // 0x17 + RIDE_MODE_LIM_POWERED_LAUNCH, RIDE_MODE_FILM_THRILL_RIDERS, RIDE_MODE_3D_FILM_STORM_CHASERS, RIDE_MODE_3D_FILM_SPACE_RAIDERS, @@ -335,7 +388,7 @@ enum { RIDE_MODE_CROOKED_HOUSE, RIDE_MODE_FREEFALL_DROP, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, - RIDE_MODE_POWERED_LAUNCH2, // 0x23. RCT2 style? + RIDE_MODE_POWERED_LAUNCH_35, // RCT2 style? RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED }; @@ -354,6 +407,115 @@ enum { RIDE_GROUP_SHOP }; +enum { + MUSIC_STYLE_DODGEMS_BEAT, + MUSIC_STYLE_FAIRGROUND_ORGAN, + MUSIC_STYLE_ROMAN_FANFARE, + MUSIC_STYLE_ORIENTAL, + MUSIC_STYLE_MARTIAN, + MUSIC_STYLE_JUNGLE_DRUMS, + MUSIC_STYLE_EGYPTIAN, + MUSIC_STYLE_TOYLAND, + MUSIC_STYLE_8, + MUSIC_STYLE_SPACE, + MUSIC_STYLE_HORROR, + MUSIC_STYLE_TECHNO, + MUSIC_STYLE_GENTLE, + MUSIC_STYLE_SUMMER, + MUSIC_STYLE_WATER, + MUSIC_STYLE_WILD_WEST, + MUSIC_STYLE_JURASSIC, + MUSIC_STYLE_ROCK, + MUSIC_STYLE_RAGTIME, + MUSIC_STYLE_FANTASY, + MUSIC_STYLE_ROCK_STYLE_2, + MUSIC_STYLE_ICE, + MUSIC_STYLE_SNOW, + MUSIC_STYLE_CUSTOM_MUSIC_1, + MUSIC_STYLE_CUSTOM_MUSIC_2, + MUSIC_STYLE_MEDIEVAL, + MUSIC_STYLE_URBAN, + MUSIC_STYLE_ORGAN, + MUSIC_STYLE_MECHANICAL, + MUSIC_STYLE_MODERN, + MUSIC_STYLE_PIRATES, + MUSIC_STYLE_ROCK_STYLE_3, + MUSIC_STYLE_CANDY_STYLE +}; + +enum { + BREAKDOWN_NONE = 255, + BREAKDOWN_SAFETY_CUT_OUT = 0, + BREAKDOWN_RESTRAINTS_STUCK_CLOSED, + BREAKDOWN_RESTRAINTS_STUCK_OPEN, + BREAKDOWN_DOORS_STUCK_CLOSED, + BREAKDOWN_DOORS_STUCK_OPEN, + BREAKDOWN_VEHICLE_MALFUNCTION, + BREAKDOWN_BRAKES_FAILURE, + BREAKDOWN_CONTROL_FAILURE +}; + +enum { + RIDE_MECHANIC_STATUS_CALLING = 1, + RIDE_MECHANIC_STATUS_HEADING = 2, + RIDE_MECHANIC_STATUS_FIXING = 3, +}; + +enum { + RIDE_DEPART_WAIT_FOR_LOAD_MASK = 7, + RIDE_DEPART_WAIT_FOR_LOAD = 1 << 3, + RIDE_DEPART_LEAVE_WHEN_ANOTHER_ARRIVES = 1 << 4, + RIDE_DEPART_SYNCHRONISE_WITH_ADJACENT_STATIONS = 1 << 5, + RIDE_DEPART_WAIT_FOR_MINIMUM_LENGTH = 1 << 6, + RIDE_DEPART_WAIT_FOR_MAXIMUM_LENGTH = 1 << 7 +}; + +enum { + RIDE_COLOUR_SCHEME_MAIN, + RIDE_COLOUR_SCHEME_ADDITIONAL_1, + RIDE_COLOUR_SCHEME_ADDITIONAL_2, + RIDE_COLOUR_SCHEME_ADDITIONAL_3 +}; + +enum { + VEHICLE_COLOUR_SCHEME_SAME, + VEHICLE_COLOUR_SCHEME_PER_TRAIN, + VEHICLE_COLOUR_SCHEME_PER_VEHICLE +}; + +enum { + RIDE_ENTRANCE_STYLE_PLAIN, + RIDE_ENTRANCE_STYLE_WOODEN, + RIDE_ENTRANCE_STYLE_CANVAS_TENT, + RIDE_ENTRANCE_STYLE_CASTLE_GREY, + RIDE_ENTRANCE_STYLE_CASTLE_BROWN, + RIDE_ENTRANCE_STYLE_JUNGLE, + RIDE_ENTRANCE_STYLE_LOG_CABIN, + RIDE_ENTRANCE_STYLE_CLASSICAL_ROMAN, + RIDE_ENTRANCE_STYLE_ABSTRACT, + RIDE_ENTRANCE_STYLE_SNOW_ICE, + RIDE_ENTRANCE_STYLE_PAGODA, + RIDE_ENTRANCE_STYLE_SPACE +}; + +typedef struct { + uint8 main; + uint8 additional; + uint8 supports; +} track_colour; + +typedef struct { + uint8 main; + uint8 additional_1; + uint8 additional_2; +} vehicle_colour; + +enum { + RIDE_MEASUREMENT_FLAG_RUNNING = 1 << 0, + RIDE_MEASUREMENT_FLAG_UNLOADING = 1 << 1, + RIDE_MEASUREMENT_FLAG_G_FORCES = 1 << 2 +}; + #define MAX_RIDES 255 #define MAX_RIDE_MEASUREMENTS 8 @@ -368,6 +530,7 @@ extern rct_ride* g_ride_list; /** Helper macros until rides are stored in this module. */ #define GET_RIDE(x) (&g_ride_list[x]) #define GET_RIDE_MEASUREMENT(x) (&(RCT2_ADDRESS(RCT2_ADDRESS_RIDE_MEASUREMENTS, rct_ride_measurement)[x])) +#define GET_RIDE_ENTRY(x) RCT2_ADDRESS(RCT2_ADDRESS_RIDE_ENTRIES, rct_ride_type*)[x] /** * Helper macro loop for enumerating through all the non null rides. @@ -387,7 +550,17 @@ void ride_update_favourited_stat(); void ride_check_all_reachable(); rct_map_element *sub_6CAF80(int rideIndex, int *outX, int *outY); rct_map_element *ride_find_track_gap(rct_map_element *startTrackElement, int *outX, int *outY); -void ride_construct_new(int list_item); +void ride_construct_new(ride_list_item listItem); int ride_try_construct(rct_map_element *trackMapElement); +void ride_get_status(int rideIndex, int *formatSecondary, int *argument); +rct_peep *ride_get_assigned_mechanic(rct_ride *ride); +int ride_get_total_length(rct_ride *ride); +int ride_can_have_multiple_circuits(rct_ride *ride); +track_colour ride_get_track_colour(rct_ride *ride, int colourScheme); +vehicle_colour ride_get_vehicle_colour(rct_ride *ride, int vehicleIndex); +rct_ride_type *ride_get_entry(rct_ride *ride); +uint8 *get_ride_entry_indices_for_ride_type(uint8 rideType); +void ride_measurements_update(); +rct_ride_measurement *ride_get_measurement(int rideIndex, rct_string_id *message); #endif diff --git a/src/ride_data.c b/src/ride/ride_data.c similarity index 51% rename from src/ride_data.c rename to src/ride/ride_data.c index aefda2a666..b1ae1d8b85 100644 --- a/src/ride_data.c +++ b/src/ride/ride_data.c @@ -9,7 +9,7 @@ */ #include -#include "rct2.h" +#include "ride.h" #include "ride_data.h" const bool hasRunningTrack[0x60] = { @@ -491,6 +491,7 @@ const bool rideUnknownData2[0x60] = { true, // 59 LIM Launched Roller Coaster }; +/* Data at 0x0097E3B8 */ const uint8 rideUnknownData3[0x60] = { 10, // 00 Spiral Roller coaster 10, // 01 Stand Up Coaster @@ -582,4 +583,192 @@ const uint8 rideUnknownData3[0x60] = { 10, // 57 Mini Roller Coaster 10, // 58 Mine Ride 10, // 59 LIM Launched Roller Coaster +}; + +const rct_ride_name_convention RideNameConvention[96] = { + { 1229, 1243, 1257, 0 }, // 00 Spiral Roller coaster + { 1229, 1243, 1257, 0 }, // 01 Stand Up Coaster + { 1229, 1243, 1257, 0 }, // 02 Suspended Swinging + { 1229, 1243, 1257, 0 }, // 03 Inverted + { 1229, 1243, 1257, 0 }, // 04 Steel Mini Coaster + { 1229, 1243, 1257, 0 }, // 05 Mini Railroad + { 1229, 1243, 1257, 0 }, // 06 Monorail + { 1264, 1243, 1257, 0 }, // 07 Mini Suspended Coaster + { 1236, 1250, 1250, 0 }, // 08 Bumper Boats + { 1264, 1243, 1257, 0 }, // 09 Wooden Wild Mine/Mouse + { 1264, 1243, 1257, 0 }, // 0a Steeplechase/Motorbike/Soap Box Derby + { 1264, 1243, 1257, 0 }, // 0b Car Ride + { 1264, 1243, 1257, 0 }, // 0c Launched Freefall + { 1229, 1243, 1257, 0 }, // 0d Bobsleigh Coaster + { 1292, 1243, 1257, 0 }, // 0e Observation Tower + { 1229, 1243, 1257, 0 }, // 0f Looping Roller Coaster + { 1236, 1243, 1257, 0 }, // 10 Dinghy Slide + { 1229, 1243, 1257, 0 }, // 11 Mine Train Coaster + { 1264, 1243, 1257, 0 }, // 12 Chairlift + { 1229, 1243, 1257, 0 }, // 13 Corkscrew Roller Coaster + { 1229, 1243, 1257, 0 }, // 14 Maze + { 1229, 1271, 1257, 0 }, // 15 Spiral Slide + { 1264, 1243, 1257, 0 }, // 16 Go Karts + { 1236, 1243, 1257, 0 }, // 17 Log Flume + { 1236, 1243, 1257, 0 }, // 18 River Rapids + { 1264, 1271, 1257, 0 }, // 19 Bumper Cars + { 1285, 1278, 1257, 0 }, // 1a Pirate Ship + { 1285, 1278, 1257, 0 }, // 1b Swinging Inverter Ship + { 1264, 1271, 1257, 0 }, // 1c Food Stall + { 1264, 1271, 1257, 0 }, // 1d (none) + { 1264, 1271, 1257, 0 }, // 1e Drink Stall + { 1264, 1271, 1257, 0 }, // 1f (none) + { 1264, 1271, 1257, 0 }, // 20 Shop (all types) + { 1264, 1278, 1257, 0 }, // 21 Merry Go Round + { 1264, 1271, 1257, 0 }, // 22 Balloon Stall (maybe) + { 1264, 1271, 1257, 0 }, // 23 Information Kiosk + { 1264, 1271, 1257, 0 }, // 24 Bathroom + { 1299, 1278, 1257, 0 }, // 25 Ferris Wheel + { 1264, 1278, 1257, 0 }, // 26 Motion Simulator + { 1271, 1278, 1257, 0 }, // 27 3D Cinema + { 1264, 1278, 1257, 0 }, // 28 Gravitron + { 1306, 1278, 1257, 0 }, // 29 Space Rings + { 1264, 1243, 1257, 0 }, // 2a Reverse Freefall Coaster + { 1292, 1243, 1257, 0 }, // 2b Elevator + { 1229, 1243, 1257, 0 }, // 2c Vertical Drop Roller Coaster + { 1264, 1271, 1257, 0 }, // 2d ATM + { 1278, 1278, 1257, 0 }, // 2e Twist + { 1271, 1278, 1257, 0 }, // 2f Haunted House + { 1264, 1271, 1257, 0 }, // 30 First Aid + { 1271, 1278, 1257, 0 }, // 31 Circus Show + { 1264, 1243, 1257, 0 }, // 32 Ghost Train + { 1229, 1243, 1257, 0 }, // 33 Twister Roller Coaster + { 1229, 1243, 1257, 0 }, // 34 Wooden Roller Coaster + { 1229, 1243, 1257, 0 }, // 35 Side-Friction Roller Coaster + { 1264, 1243, 1257, 0 }, // 36 Wild Mouse + { 1229, 1243, 1257, 0 }, // 37 Multi Dimension Coaster + { 1229, 1243, 1257, 0 }, // 38 (none) + { 1229, 1243, 1257, 0 }, // 39 Flying Roller Coaster + { 1229, 1243, 1257, 0 }, // 3a (none) + { 1264, 1243, 1257, 0 }, // 3b Virginia Reel + { 1236, 1243, 1257, 0 }, // 3c Splash Boats + { 1264, 1243, 1257, 0 }, // 3d Mini Helicopters + { 1229, 1243, 1257, 0 }, // 3e Lay-down Roller Coaster + { 1229, 1243, 1257, 0 }, // 3f Suspended Monorail + { 1229, 1243, 1257, 0 }, // 40 (none) + { 1264, 1243, 1257, 0 }, // 41 Reverser Roller Coaster + { 1264, 1243, 1257, 0 }, // 42 Heartline Twister Roller Coaster + { 1313, 1320, 1257, 0 }, // 43 Mini Golf + { 1229, 1243, 1257, 0 }, // 44 Giga Coaster + { 1264, 1243, 1257, 0 }, // 45 Roto-Drop + { 1264, 1271, 1257, 0 }, // 46 Flying Saucers + { 1271, 1278, 1257, 0 }, // 47 Crooked House + { 1264, 1243, 1257, 0 }, // 48 Monorail Cycles + { 1229, 1243, 1257, 0 }, // 49 Compact Inverted Coaster + { 1236, 1243, 1257, 0 }, // 4a Water Coaster + { 1229, 1243, 1257, 0 }, // 4b Air Powered Vertical Coaster + { 1264, 1243, 1257, 0 }, // 4c Inverted Hairpin Coaster + { 1264, 1278, 1257, 0 }, // 4d Magic Carpet + { 1236, 1243, 1250, 0 }, // 4e Submarine Ride + { 1236, 1243, 1257, 0 }, // 4f River Rafts + { 1264, 1271, 1257, 0 }, // 50 (none) + { 1299, 1278, 1257, 0 }, // 51 Enterprise + { 1264, 1271, 1257, 0 }, // 52 (none) + { 1264, 1271, 1257, 0 }, // 53 (none) + { 1264, 1271, 1257, 0 }, // 54 (none) + { 1229, 1243, 1257, 0 }, // 55 (none) + { 1229, 1243, 1257, 0 }, // 56 Inverted Impulse Coaster + { 1264, 1243, 1257, 0 }, // 57 Mini Roller Coaster + { 1229, 1243, 1257, 0 }, // 58 Mine Ride + { 1264, 1243, 1257, 0 }, // 59 LIM Launched Roller Coaster + { 1229, 1243, 1257, 0 } +}; + +const uint8 RideAvailableModes[] = { + RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 00 Spiral Roller coaster + RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 01 Stand Up Coaster + RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 02 Suspended Swinging + RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 03 Inverted + RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 04 Steel Mini Coaster + RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_SHUTTLE, 0xFF, // 05 Mini Railroad + RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_SHUTTLE, 0xFF, // 06 Monorail + RIDE_MODE_CONTINUOUS_CIRCUIT, 0xFF, // 07 Mini Suspended Coaster + RIDE_MODE_BOAT_HIRE, 0xFF, // 08 Bumper Boats + RIDE_MODE_CONTINUOUS_CIRCUIT, 0xFF, // 09 Wooden Wild Mine/Mouse + RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 0A Steeplechase/Motorbike/Soap Box Derby + RIDE_MODE_CONTINUOUS_CIRCUIT, 0xFF, // 0B Car Ride + RIDE_MODE_UPWARD_LAUNCH, RIDE_MODE_DOWNWARD_LAUNCH, 0xFF, // 0C Launched Freefall + RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 0D Bobsleigh Coaster + RIDE_MODE_ROTATING_LIFT, 0xFF, // 0E Observation Tower + RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, RIDE_MODE_REVERSE_INCLINE_LAUNCHED_SHUTTLE, RIDE_MODE_POWERED_LAUNCH, 0xFF, // 0F Looping Roller Coaster + RIDE_MODE_CONTINUOUS_CIRCUIT, 0xFF, // 10 Dinghy Slide + RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 11 Mine Train Coaster + RIDE_MODE_STATION_TO_STATION, 0xFF, // 12 Chairlift + RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0x23, 2, 0xFF, // 13 Corkscrew Roller Coaster + RIDE_MODE_MAZE, 0xFF, // 14 Maze + RIDE_MODE_SINGLE_RIDE_PER_ADMISSION, RIDE_MODE_UNLIMITED_RIDES_PER_ADMISSION, 0xFF, // 15 Spiral Slide + RIDE_MODE_RACE, RIDE_MODE_CONTINUOUS_CIRCUIT, 0xFF, // 16 Go Karts + RIDE_MODE_CONTINUOUS_CIRCUIT, 0xFF, // 17 Log Flume + RIDE_MODE_CONTINUOUS_CIRCUIT, 0xFF, // 18 River Rapids + RIDE_MODE_BUMPERCAR, 0xFF, // 19 Bumper Cars + RIDE_MODE_SWING, 0xFF, // 1A Pirate Ship + RIDE_MODE_SWING, 0xFF, // 1B Swinging Inverter Ship + RIDE_MODE_SHOP_STALL, 0xFF, // 1C Food Stall + RIDE_MODE_SHOP_STALL, 0xFF, // 1D (none) + RIDE_MODE_SHOP_STALL, 0xFF, // 1E Drink Stall + RIDE_MODE_SHOP_STALL, 0xFF, // 1F (none) + RIDE_MODE_SHOP_STALL, 0xFF, // 20 Shop (all types) + RIDE_MODE_ROTATION, 0xFF, // 21 Merry Go Round + RIDE_MODE_SHOP_STALL, 0xFF, // 22 Balloon Stall (maybe) + RIDE_MODE_SHOP_STALL, 0xFF, // 23 Information Kiosk + RIDE_MODE_SHOP_STALL, 0xFF, // 24 Bathroom + RIDE_MODE_FORWARD_ROTATION, RIDE_MODE_BACKWARD_ROTATION, 0xFF, // 25 Ferris Wheel + RIDE_MODE_FILM_AVENGING_AVIATORS, RIDE_MODE_FILM_THRILL_RIDERS, 0xFF, // 26 Motion Simulator + RIDE_MODE_3D_FILM_MOUSE_TAILS, RIDE_MODE_3D_FILM_STORM_CHASERS, RIDE_MODE_3D_FILM_SPACE_RAIDERS, 0xFF, // 27 3D Cinema + RIDE_MODE_BEGINNERS, RIDE_MODE_INTENSE, RIDE_MODE_BERSERK, 0xFF, // 28 Gravitron + RIDE_MODE_SPACE_RINGS, 0xFF, // 29 Space Rings + RIDE_MODE_LIM_POWERED_LAUNCH, 0xFF, // 2A Reverse Freefall Coaster + RIDE_MODE_SHUTTLE, 0xFF, // 2B Elevator + RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 2C Vertical Drop Roller Coaster + RIDE_MODE_SHOP_STALL, 0xFF, // 2D ATM + RIDE_MODE_ROTATION, 0xFF, // 2E Twist + RIDE_MODE_HAUNTED_HOUSE, 0xFF, // 2F Haunted House + RIDE_MODE_SHOP_STALL, 0xFF, // 30 First Aid + RIDE_MODE_CIRCUS_SHOW, 0xFF, // 31 Circus Show + RIDE_MODE_CONTINUOUS_CIRCUIT, 0xFF, // 32 Ghost Train + RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 33 Twister Roller Coaster + RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 34 Wooden Roller Coaster + RIDE_MODE_CONTINUOUS_CIRCUIT, 0xFF, // 35 Side-Friction Roller Coaster + RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 36 Wild Mouse + RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 37 Multi Dimension Coaster + RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 38 (none) + RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 39 Flying Roller Coaster + RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 3A (none) + RIDE_MODE_CONTINUOUS_CIRCUIT, 0xFF, // 3B Virginia Reel + RIDE_MODE_CONTINUOUS_CIRCUIT, 0xFF, // 3C Splash Boats + RIDE_MODE_CONTINUOUS_CIRCUIT, 0xFF, // 3D Mini Helicopters + RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 3E Lay-down Roller Coaster + RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_SHUTTLE, 0xFF, // 3F Suspended Monorail + RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 40 (none) + RIDE_MODE_CONTINUOUS_CIRCUIT, 0xFF, // 41 Reverser Roller Coaster + RIDE_MODE_CONTINUOUS_CIRCUIT, 0xFF, // 42 Heartline Twister Roller Coaster + RIDE_MODE_CONTINUOUS_CIRCUIT, 0xFF, // 43 Mini Golf + RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 44 Giga Coaster + RIDE_MODE_FREEFALL_DROP, 0xFF, // 45 Roto-Drop + RIDE_MODE_BUMPERCAR, 0xFF, // 46 Flying Saucers + RIDE_MODE_CROOKED_HOUSE, 0xFF, // 47 Crooked House + RIDE_MODE_CONTINUOUS_CIRCUIT, 0xFF, // 48 Monorail Cycles + RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 2, 0xFF, // 49 Compact Inverted Coaster + RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 4A Water Coaster + RIDE_MODE_POWERED_LAUNCH, 0xFF, // 4B Air Powered Vertical Coaster + RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 4C Inverted Hairpin Coaster + RIDE_MODE_SWING, 0xFF, // 4D Magic Carpet + RIDE_MODE_CONTINUOUS_CIRCUIT, 0xFF, // 4E Submarine Ride + RIDE_MODE_CONTINUOUS_CIRCUIT, 0xFF, // 4F River Rafts + RIDE_MODE_SHOP_STALL, 0xFF, // 50 (none) + RIDE_MODE_ROTATION, 0xFF, // 51 Enterprise + RIDE_MODE_SHOP_STALL, 0xFF, // 52 (none) + RIDE_MODE_SHOP_STALL, 0xFF, // 53 (none) + RIDE_MODE_SHOP_STALL, 0xFF, // 54 (none) + RIDE_MODE_CONTINUOUS_CIRCUIT, 0xFF, // 55 (none) + RIDE_MODE_POWERED_LAUNCH, 0xFF, // 56 Inverted Impulse Coaster + RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 57 Mini Roller Coaster + RIDE_MODE_CONTINUOUS_CIRCUIT, 0xFF, // 58 Mine Ride + RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 59 LIM Launched Roller Coaster + RIDE_MODE_POWERED_LAUNCH_35, RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED, 0xFF // 60 (none) }; \ No newline at end of file diff --git a/src/ride_data.h b/src/ride/ride_data.h similarity index 81% rename from src/ride_data.h rename to src/ride/ride_data.h index d107ad6aac..d6b1617b04 100644 --- a/src/ride_data.h +++ b/src/ride/ride_data.h @@ -22,7 +22,14 @@ #define _RIDE_DATA_H_ #include -#include "rct2.h" +#include "../common.h" + +typedef struct { + rct_string_id vehicle_name; + rct_string_id structure_name; + rct_string_id station_name; + rct_string_id unk_name; +} rct_ride_name_convention; extern const bool hasRunningTrack[0x60]; extern const uint8 initialUpkeepCosts[0x60]; @@ -32,4 +39,7 @@ extern const uint8 rideUnknownData1[0x60]; extern const bool rideUnknownData2[0x60]; extern const uint8 rideUnknownData3[0x60]; +extern const rct_ride_name_convention RideNameConvention[96]; +extern const uint8 RideAvailableModes[]; + #endif \ No newline at end of file diff --git a/src/ride_ratings.c b/src/ride/ride_ratings.c similarity index 91% rename from src/ride_ratings.c rename to src/ride/ride_ratings.c index d18fef2753..cf27fa487c 100644 --- a/src/ride_ratings.c +++ b/src/ride/ride_ratings.c @@ -18,7 +18,7 @@ * along with this program. If not, see . *****************************************************************************/ -#include "addresses.h" +#include "../addresses.h" #include "ride.h" #include "ride_data.h" #include "ride_ratings.h" @@ -56,9 +56,9 @@ void crooked_house_excitement(rct_ride *ride) ride->var_14D |= 2; // clear all bits except lowest 5 - ride->var_114 &= 0x1f; + ride->inversions &= 0x1F; // set 6th,7th,8th bits - ride->var_114 |= 0xE0; + ride->inversions |= 0xE0; } /** @@ -75,27 +75,22 @@ uint16 compute_upkeep(rct_ride *ride) uint16 upkeep = initialUpkeepCosts[ride->type]; uint16 trackCost = costPerTrackPiece[ride->type]; - uint8 dl = ride->var_115; + uint8 dl = ride->drops; dl = dl >> 6; dl = dl & 3; upkeep += trackCost * dl; - uint32 cuml = ride->var_0E4; - cuml += ride->var_0E8; - cuml += ride->var_0EC; - cuml += ride->var_0F0; - cuml = cuml >> 0x10; + uint32 totalLength = (ride->length[0] + ride->length[1] + ride->length[2] + ride->length[3]) >> 16; // The data originally here was 20's and 0's. The 20's all represented // rides that had tracks. The 0's were fixed rides like crooked house or // bumper cars. // Data source is 0x0097E3AC if (hasRunningTrack[ride->type]) { - cuml = cuml * 20; + totalLength *= 20; } - cuml = cuml >> 0x0A; - upkeep += (uint16)cuml; + upkeep += (uint16)(totalLength >> 10); if (ride->lifecycle_flags & RIDE_LIFECYCLE_ON_RIDE_PHOTO) { // The original code read from a table starting at 0x0097E3AE and @@ -130,24 +125,24 @@ uint16 compute_upkeep(rct_ride *ride) // various variables set on the ride itself. // https://gist.github.com/kevinburke/e19b803cd2769d96c540 - upkeep += rideUnknownData1[ride->type] * ride->var_0C8; + upkeep += rideUnknownData1[ride->type] * ride->num_vehicles; // either set to 3 or 0, extra boosts for some rides including mini golf if (rideUnknownData2[ride->type]) { - upkeep += 3 * ride->var_0C9; + upkeep += 3 * ride->num_cars_per_train; } // slight upkeep boosts for some rides - 5 for mini railroad, 10 for log // flume/rapids, 10 for roller coaster, 28 for giga coaster - upkeep += rideUnknownData3[ride->type] * ride->var_0C7; + upkeep += rideUnknownData3[ride->type] * ride->num_stations; - if (ride->mode == RIDE_MODE_REVERSE_INCLINED_SHUTTLE) { + if (ride->mode == RIDE_MODE_REVERSE_INCLINE_LAUNCHED_SHUTTLE) { upkeep += 30; } else if (ride->mode == RIDE_MODE_POWERED_LAUNCH) { upkeep += 160; } else if (ride->mode == RIDE_MODE_LIM_POWERED_LAUNCH) { upkeep += 320; - } else if (ride->mode == RIDE_MODE_POWERED_LAUNCH2 || + } else if (ride->mode == RIDE_MODE_POWERED_LAUNCH_35 || ride->mode == RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED) { upkeep += 220; } @@ -184,7 +179,7 @@ rating_tuple per_ride_rating_adjustments(rct_ride *ride, ride_rating excitement, // more detail: https://gist.github.com/kevinburke/d951e74e678b235eef3e uint16 ridetype_var = RCT2_GLOBAL(0x0097D4F2 + ride->type * 8, uint16); if (ridetype_var & 0x80) { - uint16 ax = ride->var_1F4; + uint16 ax = ride->total_air_time; if (rideType->var_008 & 0x800) { // 65e86e ax = ax - 96; @@ -244,7 +239,7 @@ ride_rating apply_intensity_penalty(ride_rating excitement, ride_rating intensit */ void sub_655FD6(rct_ride *ride) { - uint8 al = ride->var_1CD; + uint8 al = ride->lift_hill_speed; // No idea what this address is; maybe like compensation of some kind? The // maximum possible value? // List of ride names/values is here: diff --git a/src/ride_ratings.h b/src/ride/ride_ratings.h similarity index 98% rename from src/ride_ratings.h rename to src/ride/ride_ratings.h index 7b6463c525..14e158f564 100644 --- a/src/ride_ratings.h +++ b/src/ride/ride_ratings.h @@ -21,7 +21,7 @@ #ifndef _RIDE_RATINGS_H_ #define _RIDE_RATINGS_H_ -#include "rct2.h" +#include "../common.h" #include "ride.h" void crooked_house_excitement(rct_ride *ride); diff --git a/src/track.c b/src/ride/track.c similarity index 84% rename from src/track.c rename to src/ride/track.c index 62b3adb912..5cf6801b9a 100644 --- a/src/track.c +++ b/src/ride/track.c @@ -18,7 +18,11 @@ * along with this program. If not, see . *****************************************************************************/ -#include "addresses.h" +#include +#include +#include "../addresses.h" +#include "../platform/osinterface.h" +#include "ride.h" #include "track.h" /** @@ -220,7 +224,207 @@ const rct_trackdefinition gTrackDefinitions[] = { * * rct2: 0x006CED50 */ -void track_load_list(int edx) +void track_load_list(ride_list_item item) { - RCT2_CALLPROC_X(0x006CED50, 0, 0, 0, edx, 0, 0, 0); + RCT2_CALLPROC_X(0x006CED50, 0, 0, 0, *((uint16*)&item), 0, 0, 0); } + +/** + * + * rct2: 0x00676EBA + */ +static uint8 sub_676EBA() +{ + int eax, ebx, ecx, edx, esi, edi, ebp; + RCT2_CALLFUNC_X(0x00676EBA, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + return eax & 0xFF; +} + +/** + * + * rct2: 0x00676EAF + */ +static void sub_676EAF(uint8 *esi, int ecx) +{ + do { + *esi++ = sub_676EBA(); + } while (--ecx != 0); +} + +/** + * + * rct2: 0x0067726A + * path: 0x0141EF68 + */ +int sub_67726A(const char *path) +{ + HANDLE *hFile; + const char *ch; + char trackFilename[MAX_PATH], *dst; + int i; + uint8* edi; + + RCT2_GLOBAL(0x009AAC54, uint8) = 1; + + // Get filename + ch = strrchr(path, '\\'); + ch = ch == NULL ? path : ch + 1; + dst = trackFilename; + while (*ch != 0 && *ch != '.') { + *dst++ = *ch++; + } + *dst = 0; + + hFile = osinterface_file_open(path); + if (hFile == INVALID_HANDLE_VALUE) + return 0; + + RCT2_GLOBAL(0x009E382C, HANDLE) = hFile; + if (!RCT2_CALLPROC_X(0x006770C1, 0, 0, 0, 0, 0, 0, 0)) { + CloseHandle(hFile); + return 0; + } + + RCT2_CALLPROC_EBPSAFE(0x00676E7A); + memset((void*)0x009D81D8, 0, 67); + sub_676EAF((void*)0x009D8178, 32); + + uint8 al = RCT2_GLOBAL(0x009D817F, uint8) >> 2; + if (al >= 2) + sub_676EAF((void*)0x009D8198, 40); + + sub_676EAF((void*)0x009D81C0, 24); + al = RCT2_GLOBAL(0x009D817F, uint8) >> 2; + if (al != 0) + sub_676EAF((void*)0x009D81D8, al == 1 ? 140 : 67); + + sub_676EAF((void*)0x009D821B, 24572); + al = RCT2_GLOBAL(0x009D817F, uint8) >> 2; + if (al < 2) { + if (RCT2_GLOBAL(0x009D8178, uint8) == 20) { + edi = (uint8*)0x009D821B; + while (*edi != 0) { + edi += 4; + } + edi += 4; + memset(edi, 255, (uint8*)0x009DE217 - edi); + } else { + edi = (uint8*)0x009D821B; + while (*edi != 255) { + edi += 2; + } + edi++; + memset(edi, 255, (uint8*)0x009DE217 - edi); + } + } + + CloseHandle(hFile); + + al = RCT2_GLOBAL(0x009D817F, uint8) >> 2; + if (al > 2) + return 0; + + if (al <= 1) { + edi = (uint8*)0x009D8180; + for (i = 0; i < 67; i++) + *edi++ = RCT2_ADDRESS(0x0097F0BC, uint8)[*edi]; + + edi = (uint8*)0x009D81D8; + for (i = 0; i < 12; i++) + *edi++ = RCT2_ADDRESS(0x0097F0BC, uint8)[*edi]; + + RCT2_GLOBAL(0x009D81D2, uint8) >>= 1; + if (!RCT2_CALLPROC_X(0x00677530, 0, 0, 0, 0, 0, 0, 0)) + RCT2_GLOBAL(0x009D8178, uint8) = 255; + + if (RCT2_GLOBAL(0x009D8178, uint8) == 4) + RCT2_GLOBAL(0x009D8178, uint8) = 255; + + if (RCT2_GLOBAL(0x009D8178, uint8) == 0) + RCT2_GLOBAL(0x009D8178, uint8) = 52; + + if (RCT2_GLOBAL(0x009D8178, uint8) == 19) { + if (RCT2_GLOBAL(0x009D817E, uint8) == 3) + RCT2_GLOBAL(0x009D817E, uint8) = 35; + if (RCT2_GLOBAL(0x009D8179, uint8) == 79) { + if (RCT2_GLOBAL(0x009D817E, uint8) == 2) + RCT2_GLOBAL(0x009D817E, uint8) = 1; + } + } + + int unk1 = RCT2_GLOBAL(0x009D8179, uint8); + if (RCT2_GLOBAL(0x009D8178, uint8) == 20) { + unk1 = 0x0097F66C; + } else { + if (unk1 == 3 && RCT2_GLOBAL(0x009D8178, uint8) == 3) + unk1 = 80; + unk1 = 0x0097F0DC + (unk1 * 16); + } + + memcpy((void*)0x009D81E8, (void*)unk1, 16); + for (i = 0; i < 32; i++) + RCT2_ADDRESS(0x009D81FA, uint8)[i] = RCT2_ADDRESS(0x009D8181, uint8)[i * 2]; + + RCT2_GLOBAL(0x009D81F8, uint8) = 255; + RCT2_GLOBAL(0x009D81F9, uint8) = 255; + RCT2_GLOBAL(0x009D821A, uint8) = 5; + } + + RCT2_GLOBAL(0x009D81C8, uint8) = min( + RCT2_GLOBAL(0x009D81C8, uint8), + RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + 5 + (RCT2_GLOBAL(0x009D8178, uint8) * 8), uint8) + ); + + return 1; +} + +/** + * + * I don't think preview is a necessary output argument. It can be obtained easily using the track design structure. + * rct2: 0x006D1DEC + */ +rct_track_design *track_get_info(int index, uint8** preview) +{ + rct_track_design *trackDesign; + uint8 *trackDesignList = (uint8*)0x00F441EC; + int i; + + trackDesign = NULL; + + // Check if track design has already been loaded + for (i = 0; i < 4; i++) { + if (index == RCT2_ADDRESS(0x00F44109, uint32)[i]) { + trackDesign = &RCT2_GLOBAL(0x00F44105, rct_track_design*)[i]; + break; + } + } + + if (trackDesign == NULL) { + // Load track design + i = RCT2_GLOBAL(0x00F44119, uint32); + RCT2_GLOBAL(0x00F44119, uint32)++; + if (RCT2_GLOBAL(0x00F44119, uint32) >= 4) + RCT2_GLOBAL(0x00F44119, uint32) = 0; + + RCT2_ADDRESS(0x00F44109, uint32)[i] = index; + subsitute_path((char*)0x0141EF68, (char*)RCT2_ADDRESS_TRACKS_PATH, trackDesignList + (index * 128)); + if (!sub_67726A((char*)0x0141EF68)) { + if (preview != NULL) *preview = NULL; + return NULL; + } + + trackDesign = &RCT2_GLOBAL(0x00F44105, rct_track_design*)[i]; + + memcpy(trackDesign, (void*)0x009D8178, 163); + RCT2_CALLPROC_EBPSAFE(0x006D1EF0); + + trackDesign->cost = RCT2_GLOBAL(0x00F4411D, money32); + trackDesign->var_06 = RCT2_GLOBAL(0x00F44151, uint8) & 7; + } + + // Set preview to correct preview image based on rotation + if (preview != NULL) + *preview = trackDesign->preview[RCT2_GLOBAL(0x00F440AE, uint8)]; + + return trackDesign; +} \ No newline at end of file diff --git a/src/track.h b/src/ride/track.h similarity index 65% rename from src/track.h rename to src/ride/track.h index 40f496e1f7..e55e598c4f 100644 --- a/src/track.h +++ b/src/ride/track.h @@ -21,7 +21,8 @@ #ifndef _TRACK_H_ #define _TRACK_H_ -#include "rct2.h" +#include "../common.h" +#include "ride.h" typedef struct { uint8 type; @@ -33,6 +34,45 @@ typedef struct { uint8 pad[2]; } rct_trackdefinition; +#define TRACK_PREVIEW_IMAGE_SIZE (370 * 217) + +/** + * Track design structure. + * size: 0x4E72B + */ +typedef struct { + uint8 type; // 0x00 + uint8 pad_01; + money32 cost; // 0x02 + uint8 var_06; + uint8 var_07; + uint8 pad_08[0x42]; + uint8 total_air_time; // 0x4A + uint8 pad_4B[0x06]; + uint8 max_speed; // 0x51 + uint8 average_speed; // 0x52 + uint16 ride_length; // 0x53 + uint8 max_positive_vertical_g; // 0x55 + uint8 max_negitive_vertical_g; // 0x56 + uint8 max_lateral_g; // 0x57 + union { + uint8 inversions; // 0x58 + uint8 holes; // 0x58 + }; + uint8 drops; // 0x59 + uint8 highest_drop_height; // 0x5A + uint8 excitement; // 0x5B + uint8 intensity; // 0x5C + uint8 nausea; // 0x5D + uint8 pad_5E[0x0E]; + uint32 var_6C; + uint8 pad_70[0x10]; + uint8 space_required_x; // 0x80 + uint8 space_required_y; // 0x81 + uint8 pad_82[0x21]; + uint8 preview[4][TRACK_PREVIEW_IMAGE_SIZE]; // 0xA3 +} rct_track_design; + enum { TRACK_NONE = 0, @@ -90,6 +130,8 @@ enum { TRACK_CORKSCREW_DOWN = 224 }; -void track_load_list(int edx); +void track_load_list(ride_list_item item); +int sub_67726A(const char *path); +rct_track_design *track_get_info(int index, uint8** preview); #endif \ No newline at end of file diff --git a/src/ride/vehicle.c b/src/ride/vehicle.c new file mode 100644 index 0000000000..4b8321d083 --- /dev/null +++ b/src/ride/vehicle.c @@ -0,0 +1,589 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of OpenRCT2. + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#include "../addresses.h" +#include "../audio/audio.h" +#include "../audio/mixer.h" +#include "../interface/viewport.h" +#include "../world/sprite.h" +#include "ride.h" +#include "vehicle.h" + +static void vehicle_update(rct_vehicle *vehicle); + +/** +* +* rct2: 0x006BB9FF +*/ +void vehicle_update_sound_params(rct_vehicle* vehicle) +{ + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 2) && (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 4) || RCT2_GLOBAL(0x0141F570, uint8) == 6)) { + if (vehicle->sound1_id != (uint8)-1 || vehicle->sound2_id != (uint8)-1) { + if (vehicle->var_16.width != 0x8000) { + RCT2_GLOBAL(0x009AF5A0, rct_widthheight) = vehicle->var_16; + RCT2_GLOBAL(0x009AF5A4, rct_widthheight) = vehicle->view; + sint16 v4 = RCT2_GLOBAL(0x00F438A4, rct_viewport*)->view_x; + sint16 v5 = RCT2_GLOBAL(0x00F438A4, rct_viewport*)->view_y; + sint16 v6 = RCT2_GLOBAL(0x00F438A4, rct_viewport*)->view_width / 4; + sint16 v7 = RCT2_GLOBAL(0x00F438A4, rct_viewport*)->view_height / 4; + if (!RCT2_GLOBAL(0x00F438A8, rct_window*)->classification) { + v4 -= v6; + v5 -= v7; + } + if (v4 < RCT2_GLOBAL(0x009AF5A4, rct_widthheight).width && v5 < RCT2_GLOBAL(0x009AF5A4, rct_widthheight).height) { + sint16 t8 = RCT2_GLOBAL(0x00F438A4, rct_viewport*)->view_width + v4; + sint16 t9 = RCT2_GLOBAL(0x00F438A4, rct_viewport*)->view_height + v5; + if (!RCT2_GLOBAL(0x00F438A8, rct_window*)->classification) { + t8 += v6 + v6; + t9 += v7 + v7; + } + if (t8 >= RCT2_GLOBAL(0x009AF5A0, rct_widthheight).width && t9 >= RCT2_GLOBAL(0x009AF5A0, rct_widthheight).height) { + uint16 v9 = sub_6BC2F3(vehicle); + rct_vehicle_sound_params* i; + //for (i = RCT2_ADDRESS(0x00F438B4, rct_vehicle_sound_params); i < RCT2_GLOBAL(0x00F438B0, rct_vehicle_sound_params*) && v9 <= i->var_A; i++); + for (i = &gVehicleSoundParamsList[0]; i < gVehicleSoundParamsListEnd && v9 <= i->var_A; i++); + //if (i < RCT2_ADDRESS(0x00F43908, rct_vehicle_sound_params)) { // 0x00F43908 is end of rct_vehicle_sound_params list, which has 7 elements, not to be confused with variable at 0x00F43908 + if (i < &gVehicleSoundParamsList[countof(gVehicleSoundParamsList)]) { + //if (RCT2_GLOBAL(0x00F438B0, rct_vehicle_sound_params*) < RCT2_ADDRESS(0x00F43908, rct_vehicle_sound_params)) { + // RCT2_GLOBAL(0x00F438B0, rct_vehicle_sound_params*)++; + //} + if (gVehicleSoundParamsListEnd < &gVehicleSoundParamsList[countof(gVehicleSoundParamsList)]) { + gVehicleSoundParamsListEnd++; + } + //rct_vehicle_sound_params* j = RCT2_GLOBAL(0x00F438B0, rct_vehicle_sound_params*) - 1; + rct_vehicle_sound_params* j = gVehicleSoundParamsListEnd - 1; + while (j >= i) { + j--; + *(j + 1) = *j; + } + i->var_A = v9; + rct_widthheight v12; + v12.height = vehicle->var_16.height; + v12.width = ((uint16)RCT2_GLOBAL(0x009AF5A0, rct_widthheight).width / 2) + ((uint16)RCT2_GLOBAL(0x009AF5A4, rct_widthheight).width / 2) - RCT2_GLOBAL(0x00F438A4, rct_viewport*)->view_x; + v12.width >>= RCT2_GLOBAL(0x00F438A4, rct_viewport*)->zoom; + v12.width += RCT2_GLOBAL(0x00F438A4, rct_viewport*)->x; + + uint16 v14 = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16); + if (v14 < 64) { + v14 = 64; + } + rct_widthheight v15; + i->pan = (((((uint32)v12.width << 16) / v14) - 0x8000) >> 4); + v15.width = 0; + v15.height = (RCT2_GLOBAL(0x009AF5A0, rct_widthheight).height / 2) + (RCT2_GLOBAL(0x009AF5A4, rct_widthheight).height / 2) - RCT2_GLOBAL(0x00F438A4, rct_viewport*)->view_y; + v15.height >>= RCT2_GLOBAL(0x00F438A4, rct_viewport*)->zoom; + v15.height += RCT2_GLOBAL(0x00F438A4, rct_viewport*)->y; + + uint16 v18 = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16); + if (v18 < 64) { + v18 = 64; + } + i->var_4 = (sint16)(((v15.both / v18) - 0x8000) >> 4); + sint32 v19 = vehicle->velocity; + + int testaddr = (vehicle->var_31 * 0x65); + testaddr += (int)RCT2_ADDRESS(0x009ACFA4, rct_ride_type*)[vehicle->var_D6]; + uint8 test = ((uint8*)testaddr)[0x74]; + + if (test & 1) { + v19 *= 2; + } + if (v19 < 0) { + v19 = -v19; + } + v19 >>= 5; + v19 *= 5512; + v19 >>= 14; + v19 += 11025; + v19 += 16 * vehicle->var_BF; + i->frequency = (uint16)v19; + i->id = vehicle->sprite_index; + i->var_8 = 0; + if (vehicle->x != 0x8000) { + uint16 v22 = (vehicle->y & 0xFFE0) << 8; + v22 |= (vehicle->x & 0xFFE0 | v22) & 0xFFFF; + rct_map_element* map_element; + for (map_element = RCT2_ADDRESS(RCT2_ADDRESS_TILE_MAP_ELEMENT_POINTERS, rct_map_element*)[v22 >> 3]; map_element->type & MAP_ELEMENT_TYPE_MASK; map_element++); + if (map_element->base_height * 8 > vehicle->z) { + i->var_8 = 0x30; + } + } + } + } + } + } + } + } +} + +/** +* +* rct2: 0x006BC2F3 +*/ +int sub_6BC2F3(rct_vehicle* vehicle) +{ + int result = 0; + rct_vehicle* vehicle_temp = vehicle; + do { + result += vehicle_temp->var_46; + } while (vehicle_temp->next_vehicle_on_train != (uint16)-1 && (vehicle_temp = GET_VEHICLE(vehicle_temp->next_vehicle_on_train))); + sint32 v4 = vehicle->velocity; + if (v4 < 0) { + v4 = -v4; + } + result += ((uint16)v4) >> 13; + rct_vehicle_sound* vehicle_sound = &gVehicleSoundList[0];//RCT2_ADDRESS(RCT2_ADDRESS_VEHICLE_SOUND_LIST, rct_vehicle_sound); + while (vehicle_sound->id != vehicle->sprite_index) { + vehicle_sound++; + //if (vehicle_sound >= RCT2_GLOBAL(0x009AF42C, rct_vehicle_sound*)) { + if (vehicle_sound >= &gVehicleSoundList[countof(gVehicleSoundList)]) { + return result; + } + } + return result + 300; +} + +/** +* +* rct2: 0x006BBC6B +*/ +void vehicle_sounds_update() +{ + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SOUND_DEVICE, uint32) != -1 && !RCT2_GLOBAL(0x009AF59C, uint8) && RCT2_GLOBAL(0x009AF59D, uint8) & 1) { + RCT2_GLOBAL(0x00F438A4, rct_viewport*) = (rct_viewport*)-1; + rct_window* window = RCT2_GLOBAL(RCT2_ADDRESS_NEW_WINDOW_PTR, rct_window*); + rct_viewport* viewport = (rct_viewport*)-1; + for (window = RCT2_GLOBAL(RCT2_ADDRESS_NEW_WINDOW_PTR, rct_window*); window >= RCT2_ADDRESS(RCT2_ADDRESS_WINDOW_LIST, rct_window); window--) { + viewport = window->viewport; + if (viewport && viewport->flags & VIEWPORT_FLAG_SOUND_ON) { + break; + } + } + RCT2_GLOBAL(0x00F438A4, rct_viewport*) = viewport; + if (viewport != (rct_viewport*)-1) { + if (window) { + RCT2_GLOBAL(0x00F438A8, rct_window*) = window; + RCT2_GLOBAL(RCT2_ADDRESS_VOLUME_ADJUST_ZOOM, uint8) = 0; + if (viewport->zoom) { + RCT2_GLOBAL(RCT2_ADDRESS_VOLUME_ADJUST_ZOOM, uint8) = 35; + if (viewport->zoom != 1) { + RCT2_GLOBAL(RCT2_ADDRESS_VOLUME_ADJUST_ZOOM, uint8) = 70; + } + } + } + //label12: + //RCT2_GLOBAL(0x00F438B0, rct_vehicle_sound_params**) = &RCT2_GLOBAL(0x00F438B4, rct_vehicle_sound_params*); + gVehicleSoundParamsListEnd = &gVehicleSoundParamsList[0]; + for (uint16 i = RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_START_VEHICLE, uint16); i != SPRITE_INDEX_NULL; i = g_sprite_list[i].vehicle.next) { + vehicle_update_sound_params(&g_sprite_list[i].vehicle); + } + //printf("vehicle sounds: %d\n", (gVehicleSoundParamsListEnd - &gVehicleSoundParamsList[0])); + //RCT2_ADDRESS_VEHICLE_SOUND_LIST; + //for (rct_vehicle_sound* vehicle_sound = &RCT2_GLOBAL(RCT2_ADDRESS_VEHICLE_SOUND_LIST, rct_vehicle_sound); vehicle_sound != &RCT2_GLOBAL(0x009AF42C, rct_vehicle_sound); vehicle_sound++) { + for(int i = 0; i < countof(gVehicleSoundList); i++){ + rct_vehicle_sound* vehicle_sound = &gVehicleSoundList[i]; + if (vehicle_sound->id != (uint16)-1) { + //for (rct_vehicle_sound_params* vehicle_sound_params = &RCT2_GLOBAL(0x00F438B4, rct_vehicle_sound_params); vehicle_sound_params != RCT2_GLOBAL(0x00F438B0, rct_vehicle_sound_params*); vehicle_sound_params++) { + for (rct_vehicle_sound_params* vehicle_sound_params = &gVehicleSoundParamsList[0]; vehicle_sound_params != gVehicleSoundParamsListEnd; vehicle_sound_params++) { + if (vehicle_sound->id == vehicle_sound_params->id) { + goto label26; + } + } + if (vehicle_sound->sound1_id != (uint16)-1) { +#ifdef USE_MIXER + Mixer_Stop_Channel(vehicle_sound->sound1_channel); +#else + RCT2_GLOBAL(0x014241BC, uint32) = 1; + sound_stop(&vehicle_sound->sound1); + RCT2_GLOBAL(0x014241BC, uint32) = 0; +#endif + } + if (vehicle_sound->sound2_id != (uint16)-1) { +#ifdef USE_MIXER + Mixer_Stop_Channel(vehicle_sound->sound2_channel); +#else + RCT2_GLOBAL(0x014241BC, uint32) = 1; + sound_stop(&vehicle_sound->sound2); + RCT2_GLOBAL(0x014241BC, uint32) = 0; +#endif + } + vehicle_sound->id = (uint16)-1; + } + label26: + 1; + } + + //for (rct_vehicle_sound_params* vehicle_sound_params = &RCT2_GLOBAL(0x00F438B4, rct_vehicle_sound_params); ; vehicle_sound_params++) { + for (rct_vehicle_sound_params* vehicle_sound_params = &gVehicleSoundParamsList[0]; ; vehicle_sound_params++) { + label28: + //if (vehicle_sound_params >= RCT2_GLOBAL(0x00F438B0, rct_vehicle_sound_params*)) { + if (vehicle_sound_params >= gVehicleSoundParamsListEnd) { + return; + } + uint8 vol1 = 0xFF; + uint8 vol2 = 0xFF; + sint16 v = vehicle_sound_params->var_4; + if (v < 0) { + v = -v; + } + if (v > 0xFFF) { + v = 0xFFF; + } + v -= 0x800; + if (v > 0) { + v -= 0x400; + v = -v; + v = (uint16)v / 4; + vol1 = LOBYTE(v); + if (HIBYTE(v) != 0) { + vol1 = 0xFF; + if (HIBYTE(v) < 0) { + vol1 = 0; + } + } + } + + sint16 w = vehicle_sound_params->pan; + if (w < 0) { + w = -w; + } + if (w > 0xFFF) { + w = 0xFFF; + } + w -= 0x800; + if (w > 0) { + w -= 0x400; + w = -w; + w = (uint16)w / 4; + vol2 = LOBYTE(w); + if (HIBYTE(w) != 0) { + vol2 = 0xFF; + if (HIBYTE(w) < 0) { + vol2 = 0; + } + } + } + + if (vol1 >= vol2) { + vol1 = vol2; + } + if (vol1 < RCT2_GLOBAL(RCT2_ADDRESS_VOLUME_ADJUST_ZOOM, uint8)) { + vol1 = 0; + } else { + vol1 = vol1 - RCT2_GLOBAL(RCT2_ADDRESS_VOLUME_ADJUST_ZOOM, uint8); + } + + rct_vehicle_sound* vehicle_sound = &gVehicleSoundList[0];//&RCT2_GLOBAL(RCT2_ADDRESS_VEHICLE_SOUND_LIST, rct_vehicle_sound); + while (vehicle_sound_params->id != vehicle_sound->id) { + vehicle_sound++; + //if (vehicle_sound >= &RCT2_GLOBAL(0x009AF42C, rct_vehicle_sound)) { + if (vehicle_sound >= &gVehicleSoundList[countof(gVehicleSoundList)]) { + vehicle_sound = &gVehicleSoundList[0];//&RCT2_GLOBAL(RCT2_ADDRESS_VEHICLE_SOUND_LIST, rct_vehicle_sound); + int i = 0; + while (vehicle_sound->id != (uint16)-1) { + vehicle_sound++; + i++; + if (i >= countof(gVehicleSoundList)/*RCT2_GLOBAL(0x009AAC75, uint8)*/) { + vehicle_sound_params = (rct_vehicle_sound_params*)((int)vehicle_sound_params + 10); + goto label28; + } + } + vehicle_sound->id = vehicle_sound_params->id; + vehicle_sound->sound1_id = (uint16)-1; + vehicle_sound->sound2_id = (uint16)-1; + vehicle_sound->var_2 = 0x30; + break; + } + } + + uint8 v21 = vehicle_sound_params->var_8 & 0xFF; + uint8 v22 = vehicle_sound->var_2 & 0xFF; + if (v22 != v21) { + if (v22 < v21) { + v22 += 4; + } else { + v22 -= 4; + } + } + vehicle_sound->var_2 = v22; + if (vol1 < v22) { + vol1 = 0; + } else { + vol1 = vol1 - v22; + } + // do sound1 stuff, track noise + rct_sprite* sprite = &g_sprite_list[vehicle_sound_params->id]; + sint16 volume = sprite->vehicle.sound1_volume; + volume *= vol1; + volume = (uint16)volume / 8; + volume -= 0x1FFF; + if (volume < -10000) { + volume = -10000; + } + if (sprite->vehicle.sound1_id == (uint8)-1) { + if (vehicle_sound->sound1_id != (uint16)-1) { + vehicle_sound->sound1_id = -1; +#ifdef USE_MIXER + Mixer_Stop_Channel(vehicle_sound->sound1_channel); +#else + RCT2_GLOBAL(0x014241BC, uint32) = 1; + sound_stop(&vehicle_sound->sound1); + RCT2_GLOBAL(0x014241BC, uint32) = 0; +#endif + } + } else { + if (vehicle_sound->sound1_id == (uint16)-1) { + goto label69; + } + if (sprite->vehicle.sound1_id != vehicle_sound->sound1_id) { +#ifdef USE_MIXER + Mixer_Stop_Channel(vehicle_sound->sound1_channel); +#else + RCT2_GLOBAL(0x014241BC, uint32) = 1; + sound_stop(&vehicle_sound->sound1); + RCT2_GLOBAL(0x014241BC, uint32) = 0; +#endif + label69: + vehicle_sound->sound1_id = sprite->vehicle.sound1_id; +#ifndef USE_MIXER + RCT2_GLOBAL(0x014241BC, uint32) = 1; + sound_prepare(sprite->vehicle.sound1_id, &vehicle_sound->sound1, 1, RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_SOUND_SW_BUFFER, uint32)); + RCT2_GLOBAL(0x014241BC, uint32) = 0; +#endif + vehicle_sound->sound1_pan = vehicle_sound_params->pan; + vehicle_sound->sound1_volume = volume; + vehicle_sound->sound1_freq = vehicle_sound_params->frequency; + uint16 frequency = vehicle_sound_params->frequency; + if (RCT2_ADDRESS(0x009AF51F, uint8)[2 * sprite->vehicle.sound1_id] & 2) { + frequency = (frequency / 2) + 4000; + } + uint8 looping = RCT2_ADDRESS(0x009AF51E, uint8)[2 * sprite->vehicle.sound1_id]; + int pan = vehicle_sound_params->pan; + if (!RCT2_GLOBAL(0x009AAC6D, uint8)) { + pan = 0; + } +#ifdef USE_MIXER + vehicle_sound->sound1_channel = Mixer_Play_Effect(sprite->vehicle.sound1_id, looping ? MIXER_LOOP_INFINITE : MIXER_LOOP_NONE, DStoMixerVolume(volume), DStoMixerPan(pan), DStoMixerRate(frequency), 0); +#else + RCT2_GLOBAL(0x014241BC, uint32) = 1; + sound_play(&vehicle_sound->sound1, looping, volume, pan, frequency); + RCT2_GLOBAL(0x014241BC, uint32) = 0; +#endif + goto label87; + } + if (volume != vehicle_sound->sound1_volume) { + vehicle_sound->sound1_volume = volume; +#ifdef USE_MIXER + Mixer_Channel_Volume(vehicle_sound->sound1_channel, DStoMixerVolume(volume)); +#else + RCT2_GLOBAL(0x014241BC, uint32) = 1; + sound_set_volume(&vehicle_sound->sound1, volume); + RCT2_GLOBAL(0x014241BC, uint32) = 0; +#endif + } + if (vehicle_sound_params->pan != vehicle_sound->sound1_pan) { + vehicle_sound->sound1_pan = vehicle_sound_params->pan; + if (RCT2_GLOBAL(0x009AAC6D, uint8)) { +#ifdef USE_MIXER + Mixer_Channel_Pan(vehicle_sound->sound1_channel, DStoMixerPan(vehicle_sound_params->pan)); +#else + RCT2_GLOBAL(0x014241BC, uint32) = 1; + sound_set_pan(&vehicle_sound->sound1, vehicle_sound_params->pan); + RCT2_GLOBAL(0x014241BC, uint32) = 0; +#endif + } + } + if (!(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) & 3) && vehicle_sound_params->frequency != vehicle_sound->sound1_freq) { + vehicle_sound->sound1_freq = vehicle_sound_params->frequency; + uint16 frequency = vehicle_sound_params->frequency; + if (RCT2_GLOBAL(0x009AF51F, uint8*)[2 * sprite->vehicle.sound1_id] & 2) { + frequency = (frequency / 2) + 4000; + } +#ifdef USE_MIXER + Mixer_Channel_Rate(vehicle_sound->sound1_channel, DStoMixerRate(frequency)); +#else + RCT2_GLOBAL(0x014241BC, uint32) = 1; + sound_set_frequency(&vehicle_sound->sound1, frequency); + RCT2_GLOBAL(0x014241BC, uint32) = 0; +#endif + } + } + label87: // do sound2 stuff, screams + sprite = &g_sprite_list[vehicle_sound_params->id]; + volume = sprite->vehicle.sound2_volume; + volume *= vol1; + volume = (uint16)volume / 8; + volume -= 0x1FFF; + if (volume < -10000) { + volume = -10000; + } + if (sprite->vehicle.sound2_id == (uint8)-1) { + if (vehicle_sound->sound2_id != (uint16)-1) { + vehicle_sound->sound2_id = -1; +#ifdef USE_MIXER + Mixer_Stop_Channel(vehicle_sound->sound2_channel); +#else + RCT2_GLOBAL(0x014241BC, uint32) = 1; + sound_stop(&vehicle_sound->sound2); + RCT2_GLOBAL(0x014241BC, uint32) = 0; +#endif + } + } else { + if (vehicle_sound->sound2_id == (uint16)-1) { + goto label93; + } + if (sprite->vehicle.sound2_id != vehicle_sound->sound2_id) { +#ifdef USE_MIXER + Mixer_Stop_Channel(vehicle_sound->sound2_channel); +#else + RCT2_GLOBAL(0x014241BC, uint32) = 1; + sound_stop(&vehicle_sound->sound2); + RCT2_GLOBAL(0x014241BC, uint32) = 0; +#endif + label93: + vehicle_sound->sound2_id = sprite->vehicle.sound2_id; +#ifndef USE_MIXER + RCT2_GLOBAL(0x014241BC, uint32) = 1; + sound_prepare(sprite->vehicle.sound2_id, &vehicle_sound->sound2, 1, RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_SOUND_SW_BUFFER, uint32)); + RCT2_GLOBAL(0x014241BC, uint32) = 0; +#endif + vehicle_sound->sound2_pan = vehicle_sound_params->pan; + vehicle_sound->sound2_volume = volume; + vehicle_sound->sound2_freq = vehicle_sound_params->frequency; + uint16 frequency = vehicle_sound_params->frequency; + if (RCT2_ADDRESS(0x009AF51F, uint8)[2 * sprite->vehicle.sound2_id] & 1) { + frequency = 12649; + } + frequency = (frequency * 2) - 3248; + if (frequency > 25700) { + frequency = 25700; + } + uint8 looping = RCT2_ADDRESS(0x009AF51E, uint8)[2 * sprite->vehicle.sound2_id]; + int pan = vehicle_sound_params->pan; + if (!RCT2_GLOBAL(0x009AAC6D, uint8)) { + pan = 0; + } +#ifdef USE_MIXER + vehicle_sound->sound2_channel = Mixer_Play_Effect(sprite->vehicle.sound2_id, looping ? MIXER_LOOP_INFINITE : MIXER_LOOP_NONE, DStoMixerVolume(volume), DStoMixerPan(pan), DStoMixerRate(frequency), 0); +#else + RCT2_GLOBAL(0x014241BC, uint32) = 1; + sound_play(&vehicle_sound->sound2, looping, volume, pan, frequency); + RCT2_GLOBAL(0x014241BC, uint32) = 0; +#endif + goto label114; + } + if (volume != vehicle_sound->sound2_volume) { +#ifdef USE_MIXER + Mixer_Channel_Volume(vehicle_sound->sound2_channel, DStoMixerVolume(volume)); +#else + RCT2_GLOBAL(0x014241BC, uint32) = 1; + sound_set_volume(&vehicle_sound->sound2, volume); + RCT2_GLOBAL(0x014241BC, uint32) = 0; +#endif + vehicle_sound->sound2_volume = volume; + } + if (vehicle_sound_params->pan != vehicle_sound->sound2_pan) { + vehicle_sound->sound2_pan = vehicle_sound_params->pan; + if (RCT2_GLOBAL(0x009AAC6D, uint8)) { +#ifdef USE_MIXER + Mixer_Channel_Pan(vehicle_sound->sound2_channel, DStoMixerPan(vehicle_sound_params->pan)); +#else + RCT2_GLOBAL(0x014241BC, uint32) = 1; + sound_set_pan(&vehicle_sound->sound2, vehicle_sound_params->pan); + RCT2_GLOBAL(0x014241BC, uint32) = 0; +#endif + } + } + if (!(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) & 3) && vehicle_sound_params->frequency != vehicle_sound->sound2_freq) { + vehicle_sound->sound2_freq = vehicle_sound_params->frequency; + if (!(RCT2_ADDRESS(0x009AF51F, uint8)[2 * sprite->vehicle.sound2_id] & 1)) { + uint16 frequency = (vehicle_sound_params->frequency * 2) - 3248; + if (frequency > 25700) { + frequency = 25700; + } +#ifdef USE_MIXER + Mixer_Channel_Rate(vehicle_sound->sound2_channel, DStoMixerRate(frequency)); +#else + RCT2_GLOBAL(0x014241BC, uint32) = 1; + sound_set_frequency(&vehicle_sound->sound2, frequency); + RCT2_GLOBAL(0x014241BC, uint32) = 0; +#endif + + } + } + } + label114: + 1; + } + } + } +} + +/** + * + * rct2: 0x006D4204 + */ +void vehicle_update_all() +{ + uint16 sprite_index; + rct_vehicle *vehicle; + + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 2) + return; + + if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 4) && RCT2_GLOBAL(0x0141F570, uint8) != 6) + return; + + + sprite_index = RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_START_VEHICLE, uint16); + while (sprite_index != SPRITE_INDEX_NULL) { + vehicle = &(g_sprite_list[sprite_index].vehicle); + sprite_index = vehicle->next; + + vehicle_update(vehicle); + } +} + +/** + * + * rct2: 0x006D77F2 + */ +static void vehicle_update(rct_vehicle *vehicle) +{ + RCT2_CALLPROC_X(0x006D77F2, 0, 0, 0, 0, (int)vehicle, 0, 0); +} + +/** + * + * rct2: 0x006D73D0 + * ax: verticalG + * dx: lateralG + * esi: vehicle + */ +void vehicle_get_g_forces(rct_vehicle *vehicle, int *verticalG, int *lateralG) +{ + int eax, ebx, ecx, edx, esi, edi, ebp; + + esi = (int)vehicle; + RCT2_CALLFUNC_X(0x006D73D0, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + + if (verticalG != NULL) *verticalG = (sint16)(eax & 0xFFFF); + if (lateralG != NULL) *lateralG = (sint16)(edx & 0xFFFF); +} \ No newline at end of file diff --git a/src/ride/vehicle.h b/src/ride/vehicle.h new file mode 100644 index 0000000000..4839a014d1 --- /dev/null +++ b/src/ride/vehicle.h @@ -0,0 +1,133 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of OpenRCT2. + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#ifndef _VEHICLE_H_ +#define _VEHICLE_H_ + +#include "../common.h" + +typedef union { + struct { + sint16 width; + sint16 height; + }; + sint32 both; +} rct_widthheight; + +typedef struct { + uint8 sprite_identifier; // 0x00 + uint8 pad_01[0x03]; + uint16 next; // 0x04 + uint16 previous; // 0x06 + uint8 linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_... + uint8 pad_09; + uint16 sprite_index; // 0x0A + uint8 pad_0C[2]; + sint16 x; // 0x0E + sint16 y; // 0x10 + sint16 z; // 0x12 + uint8 pad_14[0x02]; + rct_widthheight var_16; + rct_widthheight view; // 0x1A + uint16 var_1E; + uint8 pad_20[0x08]; + sint32 velocity; // 0x28 + uint8 pad_2C[0x04]; + uint8 ride; // 0x30 + uint8 var_31; + uint8 pad_32[0x02]; + uint16 var_34; + sint16 var_36; + uint8 pad_38[0x06]; + uint16 next_vehicle_on_train; // 0x3E + uint32 var_40; + uint16 var_44; + uint16 var_46; + uint16 var_48; + uint8 pad_4A; + uint8 var_4B; + uint8 pad_4C[0x4]; + uint8 status; // 0x50 + uint8 var_51; + uint16 peep; // 0x52 + uint8 pad_54[0x2C]; + uint16 var_80; + uint8 pad_82[0x31]; + uint8 var_B3; + uint8 pad_B4[0x07]; + uint8 sound1_id; // 0xBB + uint8 sound1_volume; // 0xBC + uint8 sound2_id; // 0xBD + uint8 sound2_volume; // 0xBE + sint8 var_BF; + uint8 pad_C0[0x02]; + uint8 speed; // 0xC2 + uint8 pad_C3[0x09]; + uint8 var_CC; + uint8 var_CD; + uint8 var_CE; + uint8 pad_CF[0x07]; + uint8 var_D6; +} rct_vehicle; + +enum { + VEHICLE_STATUS_MOVING_TO_END_OF_STATION, + VEHICLE_STATUS_WAITING_FOR_PASSENGERS, + VEHICLE_STATUS_WAITING_TO_DEPART, + VEHICLE_STATUS_DEPARTING, + VEHICLE_STATUS_TRAVELLING, + VEHICLE_STATUS_ARRIVING, + VEHICLE_STATUS_UNLOADING_PASSENGERS, + VEHICLE_STATUS_TRAVELLING_07, + VEHICLE_STATUS_CRASHING, + VEHICLE_STATUS_CRASHED, + VEHICLE_STATUS_TRAVELLING_0A, + VEHICLE_STATUS_SWINGING, + VEHICLE_STATUS_ROTATING, + VEHICLE_STATUS_ROTATING_0D, + VEHICLE_STATUS_OPERATING, + VEHICLE_STATUS_SHOWING_FILM, + VEHICLE_STATUS_ROTATING_10, + VEHICLE_STATUS_OPERATING_11, + VEHICLE_STATUS_OPERATING_12, + VEHICLE_STATUS_DOING_CIRCUS_SHOW, + VEHICLE_STATUS_OPERATING_13, + VEHICLE_STATUS_WAITING_FOR_CABLE_LIFT, + VEHICLE_STATUS_TRAVELLING_15, + VEHICLE_STATUS_STOPPING, + VEHICLE_STATUS_WAITING_FOR_PASSENGERS_17, + VEHICLE_STATUS_WAITING_TO_START, + VEHICLE_STATUS_STARTING, + VEHICLE_STATUS_OPERATING_1A, + VEHICLE_STATUS_STOPPING_1B, + VEHICLE_STATUS_UNLOADING_PASSENGERS_1C, + VEHICLE_STATUS_STOPPED_BY_BLOCK_BRAKES +}; + +void vehicle_update_all(); +int sub_6BC2F3(rct_vehicle* vehicle); +void sub_6BB9FF(rct_vehicle* vehicle); +void vehicle_sounds_update(); +void vehicle_get_g_forces(rct_vehicle *vehicle, int *verticalG, int *lateralG); + +/** Helper macro until rides are stored in this module. */ +#define GET_VEHICLE(sprite_index) &(g_sprite_list[sprite_index].vehicle) + +#endif \ No newline at end of file diff --git a/src/sawyercoding.c b/src/sawyercoding.c deleted file mode 100644 index 10af63d500..0000000000 --- a/src/sawyercoding.c +++ /dev/null @@ -1,188 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014 Ted John - * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. - * - * This file is part of OpenRCT2. - * - * OpenRCT2 is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *****************************************************************************/ - -#include -#include -#include "addresses.h" -#include "rct2.h" -#include "sawyercoding.h" - -static int decode_chunk_rle(char *buffer, int length); -static int decode_chunk_repeat(char *buffer, int length); -static void decode_chunk_rotate(char *buffer, int length); - -/** - * - * rct2: 0x00676FD2 - */ -int sawyercoding_validate_checksum(FILE *file) -{ - uint32 i, checksum, fileChecksum, dataSize, bufferSize; - uint8 buffer[1024]; - - // Get data size - fseek(file, 0, SEEK_END); - dataSize = ftell(file); - if (dataSize < 8) - return 0; - dataSize -= 4; - - // Calculate checksum - fseek(file, 0, SEEK_SET); - checksum = 0; - do { - bufferSize = min(dataSize, 1024); - if (fread(buffer, bufferSize, 1, file) != 1) - return 0; - - for (i = 0; i < bufferSize; i++) - checksum += buffer[i]; - dataSize -= bufferSize; - } while (dataSize != 0); - - // Read file checksum - if (fread(&fileChecksum, sizeof(fileChecksum), 1, file) != 1) - return 0; - - // Reset file position - fseek(file, 0, SEEK_SET); - - // Validate - return checksum == fileChecksum; -} - -/** - * - * rct2: 0x0067685F - * buffer (esi) - */ -int sawyercoding_read_chunk(FILE *file, uint8 *buffer) -{ - sawyercoding_chunk_header chunkHeader; - - // Read chunk header - if (fread(&chunkHeader, sizeof(sawyercoding_chunk_header), 1, file) != 1) { - RCT2_ERROR("Unable to read chunk header!"); - return -1; - } - - // Read chunk data - if (fread(buffer, chunkHeader.length, 1, file) != 1) { - RCT2_ERROR("Unable to read chunk data!"); - return -1; - } - - // Decode chunk data - switch (chunkHeader.encoding) { - case CHUNK_ENCODING_RLE: - chunkHeader.length = decode_chunk_rle(buffer, chunkHeader.length); - break; - case CHUNK_ENCODING_RLECOMPRESSED: - chunkHeader.length = decode_chunk_rle(buffer, chunkHeader.length); - chunkHeader.length = decode_chunk_repeat(buffer, chunkHeader.length); - break; - case CHUNK_ENCODING_ROTATE: - decode_chunk_rotate(buffer, chunkHeader.length); - break; - } - - // Set length - RCT2_GLOBAL(0x009E3828, uint32) = chunkHeader.length; - return chunkHeader.length; -} - -/** - * - * rct2: 0x0067693A - */ -static int decode_chunk_rle(char *buffer, int length) -{ - int i, j, count; - unsigned char *src, *dst, rleCodeByte; - - // Backup buffer - src = malloc(length); - memcpy(src, buffer, length); - dst = buffer; - - for (i = 0; i < length; i++) { - rleCodeByte = src[i]; - if (rleCodeByte & 128) { - i++; - count = 257 - rleCodeByte; - for (j = 0; j < count; j++) - *dst++ = src[i]; - } else { - for (j = 0; j <= rleCodeByte; j++) - *dst++ = src[++i]; - } - } - - // Free backup buffer - free(src); - - // Return final size - return (char*)dst - buffer; -} - -/** - * - * rct2: 0x006769F1 - */ -static int decode_chunk_repeat(char *buffer, int length) -{ - int i, j, count; - unsigned char *src, *dst, *copyOffset; - - // Backup buffer - src = malloc(length); - memcpy(src, buffer, length); - dst = buffer; - - for (i = 0; i < length; i++) { - if (src[i] == 0xFF) { - *dst++ = src[++i]; - } else { - count = (src[i] & 7) + 1; - copyOffset = dst + (int)(src[i] >> 3) - 32; - for (j = 0; j < count; j++) - *dst++ = *copyOffset++; - } - } - - // Free backup buffer - free(src); - - // Return final size - return (char*)dst - buffer; -} - -/** - * - * rct2: 0x006768F4 - */ -static void decode_chunk_rotate(char *buffer, int length) -{ - int i, code = 1; - for (i = 0; i < length; i++) { - buffer[i] = ror8(buffer[i], code); - code = (code + 2) % 8; - } -} diff --git a/src/scenario.c b/src/scenario.c index c83c136f8b..41de056a7a 100644 --- a/src/scenario.c +++ b/src/scenario.c @@ -21,22 +21,21 @@ #include #include #include "addresses.h" -#include "award.h" -#include "date.h" -#include "finance.h" #include "game.h" -#include "map.h" -#include "marketing.h" -#include "news_item.h" +#include "interface/viewport.h" +#include "localisation/date.h" +#include "localisation/localisation.h" +#include "management/award.h" +#include "management/finance.h" +#include "management/marketing.h" +#include "management/news_item.h" #include "object.h" -#include "park.h" -#include "rct2.h" -#include "ride.h" -#include "sawyercoding.h" +#include "ride/ride.h" #include "scenario.h" -#include "string_ids.h" -#include "sprite.h" -#include "viewport.h" +#include "util/sawyercoding.h" +#include "world/map.h" +#include "world/park.h" +#include "world/sprite.h" /** * Loads only the basic information from a scenario. @@ -109,7 +108,7 @@ int scenario_load(const char *path) if (s6Header->num_packed_objects > 0) { j = 0; for (i = 0; i < s6Header->num_packed_objects; i++) - j += object_load_packed(); + j += object_load_packed(file); if (j > 0) object_list_load(); } @@ -192,7 +191,7 @@ int scenario_load_and_play_from_path(const char *path) srand0 = RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_SRAND_0, uint32) ^ timeGetTime(); srand1 = RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_SRAND_1, uint32) ^ timeGetTime(); - RCT2_CALLPROC_EBPSAFE(0x006CBCC3); + window_close_construction_windows(); if (!scenario_load(path)) return 0; @@ -425,13 +424,7 @@ void scenario_objective8_check() ride->status == RIDE_STATUS_OPEN && ride->excitement >= RIDE_RATING(7,00) && type_already_counted[subtype_id] == 0){ - // this calculates the length, no idea why it's done so complicated though. - uint8 limit = ride->pad_088[63]; - uint32 sum = 0; - for (int j = 0; j < limit; ++j) { - sum += ((uint32*)&ride->pad_088[92])[j]; - } - if ((sum >> 16) > (uint32)objective_length) { + if ((ride_get_total_length(ride) >> 16) > objective_length) { type_already_counted[subtype_id]++; rcs++; } diff --git a/src/scenario.h b/src/scenario.h index 7d061cc061..80e145d9b1 100644 --- a/src/scenario.h +++ b/src/scenario.h @@ -176,14 +176,15 @@ typedef struct { uint8 guests_in_park_history[32]; // SC6[10] - uint16 word_01357CF2; - uint32 word_01357CF4; + uint8 active_research_types; + uint8 research_progress_stage; + uint32 dword_01357CF4; uint8 byte_01357CF8[1000]; - uint32 dword_013580E0[32]; - uint16 word_013580E4[16]; - uint8 byte_013580E6; - uint8 byte_013580E7; - uint8 byte_013580E8; + uint32 dword_013580E0; + uint16 research_progress; + uint8 next_research_category; + uint8 next_research_expected_day; + uint8 next_research_expected_month; uint8 byte_013580E9; uint16 park_size; uint16 guest_generation_probability; @@ -330,7 +331,7 @@ typedef struct { uint8 ride_measurements[0x25860]; uint32 dword_13B0E6C; uint16 word_13B0E70; - uint32 dword_13B0E72[0x6600]; + uint32 dword_13B0E72[0x6600]; // 512 bytes per staff peep uint8 byte_13CA672[116]; uint8 byte_13CA6E6[84]; uint8 byte_13CA73A[4]; diff --git a/src/sprites.h b/src/sprites.h index ba86b98915..78116c46d0 100644 --- a/src/sprites.h +++ b/src/sprites.h @@ -44,6 +44,8 @@ enum { SPR_RESIZE = 5058, + SPR_CONSTRUCTION = 5164, + SPR_DEMOLISH = 5165, SPR_HEARING_VIEWPORT = 5166, SPR_LOCATE = 5167, SPR_RENAME = 5168, diff --git a/src/title.c b/src/title.c index 29f7c86774..de0ccf685d 100644 --- a/src/title.c +++ b/src/title.c @@ -22,23 +22,22 @@ #include #include #include "addresses.h" -#include "audio.h" +#include "audio/audio.h" #include "config.h" -#include "climate.h" -#include "date.h" -#include "game.h" -#include "gfx.h" -#include "intro.h" -#include "map.h" -#include "news_item.h" -#include "park.h" -#include "rct2.h" -#include "ride.h" -#include "scenario.h" -#include "sprite.h" -#include "string_ids.h" -#include "viewport.h" +#include "drawing/drawing.h" #include "editor.h" +#include "localisation/date.h" +#include "localisation/localisation.h" +#include "game.h" +#include "interface/viewport.h" +#include "intro.h" +#include "management/news_item.h" +#include "ride/ride.h" +#include "scenario.h" +#include "world/climate.h" +#include "world/map.h" +#include "world/park.h" +#include "world/sprite.h" static const int gOldMusic = 0; static const int gRandomShowcase = 0; @@ -109,7 +108,7 @@ void title_load() RCT2_CALLPROC_EBPSAFE(0x006DFEE4); window_new_ride_init_vars(); window_guest_list_init_vars_b(); - window_staff_init_vars(); + window_staff_list_init_vars(); map_update_tile_pointers(); //RCT2_CALLPROC_EBPSAFE(0x0068AFFD); reset_0x69EBE4();// RCT2_CALLPROC_EBPSAFE(0x0069EBE4); viewport_init_all(); @@ -290,7 +289,7 @@ void title_update() // RCT2_CALLPROC_EBPSAFE(0x006EA627); // window_manager_handle_input(); game_handle_input(); - update_water_animation(); + update_palette_effects(); update_rain_animation(); if (RCT2_GLOBAL(0x009AAC73, uint8) != 255) { diff --git a/src/tutorial.c b/src/tutorial.c index b6cb100493..fe42977286 100644 --- a/src/tutorial.c +++ b/src/tutorial.c @@ -20,8 +20,9 @@ #include #include "addresses.h" +#include "localisation/localisation.h" #include "tutorial.h" -#include "window_error.h" +#include "windows/error.h" /** * @@ -30,7 +31,7 @@ void tutorial_start(int type) { strcpy((char*)0x009BC677, "Tutorial not implemented."); - window_error_open(3165, -1); + window_error_open(3165, STR_NONE); // RCT2_CALLPROC_X(0x0066ECC1, type, 0, 0, 0, 0, 0, 0); } diff --git a/src/util/sawyercoding.c b/src/util/sawyercoding.c new file mode 100644 index 0000000000..5443b2c4b9 --- /dev/null +++ b/src/util/sawyercoding.c @@ -0,0 +1,305 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of OpenRCT2. + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#include +#include +#include "../addresses.h" +#include "sawyercoding.h" + +static int decode_chunk_rle(uint8* src_buffer, uint8* dst_buffer, int length); +static int decode_chunk_repeat(char *buffer, int length); +static void decode_chunk_rotate(char *buffer, int length); + +int encode_chunk_rle(char *src_buffer, char *dst_buffer, int length); +void encode_chunk_rotate(char *buffer, int length); + +int sawyercoding_calculate_checksum(uint8* buffer, uint32 length){ + int checksum = 0; + do { + int bufferSize = min(length , 1024); + + for (int i = 0; i < bufferSize; i++) + checksum += buffer[i]; + length -= bufferSize; + } while (length != 0); + + return checksum; +} + +/** + * + * rct2: 0x00676FD2 + */ +int sawyercoding_validate_checksum(FILE *file) +{ + uint32 i, checksum, fileChecksum, dataSize, bufferSize; + uint8 buffer[1024]; + + // Get data size + fseek(file, 0, SEEK_END); + dataSize = ftell(file); + if (dataSize < 8) + return 0; + dataSize -= 4; + + // Calculate checksum + fseek(file, 0, SEEK_SET); + checksum = 0; + do { + bufferSize = min(dataSize, 1024); + if (fread(buffer, bufferSize, 1, file) != 1) + return 0; + + for (i = 0; i < bufferSize; i++) + checksum += buffer[i]; + dataSize -= bufferSize; + } while (dataSize != 0); + + // Read file checksum + if (fread(&fileChecksum, sizeof(fileChecksum), 1, file) != 1) + return 0; + + // Reset file position + fseek(file, 0, SEEK_SET); + + // Validate + return checksum == fileChecksum; +} + + +/** + * + * rct2: 0x0067685F + * buffer (esi) + */ +int sawyercoding_read_chunk(FILE *file, uint8 *buffer) +{ + sawyercoding_chunk_header chunkHeader; + + // Read chunk header + if (fread(&chunkHeader, sizeof(sawyercoding_chunk_header), 1, file) != 1) { + RCT2_ERROR("Unable to read chunk header!"); + return -1; + } + + uint8* src_buffer = malloc(chunkHeader.length); + + // Read chunk data + if (fread(src_buffer, chunkHeader.length, 1, file) != 1) { + free(src_buffer); + RCT2_ERROR("Unable to read chunk data!"); + return -1; + } + + // Decode chunk data + switch (chunkHeader.encoding) { + case CHUNK_ENCODING_NONE: + memcpy(buffer, src_buffer, chunkHeader.length); + break; + case CHUNK_ENCODING_RLE: + chunkHeader.length = decode_chunk_rle(src_buffer, buffer, chunkHeader.length); + break; + case CHUNK_ENCODING_RLECOMPRESSED: + chunkHeader.length = decode_chunk_rle(src_buffer, buffer, chunkHeader.length); + chunkHeader.length = decode_chunk_repeat(buffer, chunkHeader.length); + break; + case CHUNK_ENCODING_ROTATE: + memcpy(buffer, src_buffer, chunkHeader.length); + decode_chunk_rotate(buffer, chunkHeader.length); + break; + } + free(src_buffer); + // Set length + RCT2_GLOBAL(0x009E3828, uint32) = chunkHeader.length; + return chunkHeader.length; +} + +/** + * + * rct2: 0x0067693A + */ +static int decode_chunk_rle(uint8* src_buffer, uint8* dst_buffer, int length) +{ + int i, j, count; + uint8 *dst, rleCodeByte; + + dst = dst_buffer; + + for (i = 0; i < length; i++) { + rleCodeByte = src_buffer[i]; + if (rleCodeByte & 128) { + i++; + count = 257 - rleCodeByte; + for (j = 0; j < count; j++) + *dst++ = src_buffer[i]; + } else { + for (j = 0; j <= rleCodeByte; j++) + *dst++ = src_buffer[++i]; + } + } + + // Return final size + return dst - dst_buffer; +} + +/** + * + * rct2: 0x006769F1 + */ +static int decode_chunk_repeat(char *buffer, int length) +{ + int i, j, count; + unsigned char *src, *dst, *copyOffset; + + // Backup buffer + src = malloc(length); + memcpy(src, buffer, length); + dst = buffer; + + for (i = 0; i < length; i++) { + if (src[i] == 0xFF) { + *dst++ = src[++i]; + } else { + count = (src[i] & 7) + 1; + copyOffset = dst + (int)(src[i] >> 3) - 32; + for (j = 0; j < count; j++) + *dst++ = *copyOffset++; + } + } + + // Free backup buffer + free(src); + + // Return final size + return (char*)dst - buffer; +} + +/** + * + * rct2: 0x006768F4 + */ +static void decode_chunk_rotate(char *buffer, int length) +{ + int i, code = 1; + for (i = 0; i < length; i++) { + buffer[i] = ror8(buffer[i], code); + code = (code + 2) % 8; + } +} + +/** +* +* rct2: 0x006762E1 +* +*/ +int sawyercoding_write_chunk_buffer(uint8 *dst_file, uint8* buffer, sawyercoding_chunk_header chunkHeader){ + uint8* encode_buffer; + + switch (chunkHeader.encoding){ + case CHUNK_ENCODING_NONE: + memcpy(dst_file, &chunkHeader, sizeof(sawyercoding_chunk_header)); + dst_file += sizeof(sawyercoding_chunk_header); + memcpy(dst_file, buffer, chunkHeader.length); + //fwrite(&chunkHeader, sizeof(sawyercoding_chunk_header), 1, file); + //fwrite(buffer, 1, chunkHeader.length, file); + break; + case CHUNK_ENCODING_RLE: + encode_buffer = malloc(0x600000); + chunkHeader.length = encode_chunk_rle(buffer, encode_buffer, chunkHeader.length); + memcpy(dst_file, &chunkHeader, sizeof(sawyercoding_chunk_header)); + dst_file += sizeof(sawyercoding_chunk_header); + memcpy(dst_file, encode_buffer, chunkHeader.length); + + free(encode_buffer); + break; + case CHUNK_ENCODING_RLECOMPRESSED: + RCT2_ERROR("This has not been implemented"); + return -1; + //chunkHeader.length = decode_chunk_rle(src_buffer, buffer, chunkHeader.length); + //chunkHeader.length = decode_chunk_repeat(buffer, chunkHeader.length); + break; + case CHUNK_ENCODING_ROTATE: + encode_chunk_rotate(buffer, chunkHeader.length); + memcpy(dst_file, &chunkHeader, sizeof(sawyercoding_chunk_header)); + dst_file += sizeof(sawyercoding_chunk_header); + memcpy(dst_file, buffer, chunkHeader.length); + break; + } + + return chunkHeader.length + sizeof(sawyercoding_chunk_header); +} + +/** +* Ensure dst_buffer is bigger than src_buffer then resize afterwards +* returns length of dst_buffer +*/ +int encode_chunk_rle(char *src_buffer, char *dst_buffer, int length) +{ + char* src = src_buffer; + char* dst = dst_buffer; + char* end_src = src + length; + uint8 count = 0; + char* src_norm_start = src; + + while (src < end_src - 1){ + + if ((count && *src == src[1]) || count > 120){ + *dst++ = count - 1; + for (; count != 0; --count){ + *dst++ = *src_norm_start++; + } + } + if (*src == src[1]){ + for (; (count < 120) && ((src + count) < end_src); count++){ + if (*src != src[count]) break; + } + *dst++ = 257 - count; + *dst++ = *src; + src += count; + src_norm_start = src; + count = 0; + } + else{ + count++; + src++; + } + } + if (src == end_src - 1)count++; + if (count){ + *dst++ = count - 1; + for (; count != 0; --count){ + *dst++ = *src_norm_start++; + } + } + return dst - dst_buffer; +} + +/** +* +* +*/ +void encode_chunk_rotate(char *buffer, int length) +{ + int i, code = 1; + for (i = 0; i < length; i++) { + buffer[i] = rol8(buffer[i], code); + code = (code + 2) % 8; + } +} diff --git a/src/sawyercoding.h b/src/util/sawyercoding.h similarity index 86% rename from src/sawyercoding.h rename to src/util/sawyercoding.h index 38916cf1c3..7f990c589e 100644 --- a/src/sawyercoding.h +++ b/src/util/sawyercoding.h @@ -22,7 +22,7 @@ #define _SAWYERCODING_H_ #include -#include "rct2.h" +#include "../common.h" typedef struct { uint8 encoding; @@ -37,6 +37,8 @@ enum { }; int sawyercoding_validate_checksum(FILE *file); +int sawyercoding_calculate_checksum(uint8* buffer, uint32 length); int sawyercoding_read_chunk(FILE *file, uint8 *buffer); +int sawyercoding_write_chunk_buffer(uint8 *dst_file, uint8* buffer, sawyercoding_chunk_header chunkHeader); #endif diff --git a/src/util.c b/src/util/util.c similarity index 100% rename from src/util.c rename to src/util/util.c diff --git a/src/util.h b/src/util/util.h similarity index 100% rename from src/util.h rename to src/util/util.h diff --git a/src/vehicle.c b/src/vehicle.c deleted file mode 100644 index 2bf9f92029..0000000000 --- a/src/vehicle.c +++ /dev/null @@ -1,59 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014 Ted John - * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. - * - * This file is part of OpenRCT2. - * - * OpenRCT2 is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *****************************************************************************/ - -#include "addresses.h" -#include "sprite.h" -#include "vehicle.h" - -static void vehicle_update(rct_vehicle *vehicle); - -/** - * - * rct2: 0x006D4204 - */ -void vehicle_update_all() -{ - uint16 sprite_index; - rct_vehicle *vehicle; - - if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 2) - return; - - if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 4) && RCT2_GLOBAL(0x0141F570, uint8) != 6) - return; - - - sprite_index = RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_START_VEHICLE, uint16); - while (sprite_index != SPRITE_INDEX_NULL) { - vehicle = &(g_sprite_list[sprite_index].vehicle); - sprite_index = vehicle->next; - - vehicle_update(vehicle); - } -} - -/** - * - * rct2: 0x006D77F2 - */ -static void vehicle_update(rct_vehicle *vehicle) -{ - RCT2_CALLPROC_X(0x006D77F2, 0, 0, 0, 0, (int)vehicle, 0, 0); -} \ No newline at end of file diff --git a/src/vehicle.h b/src/vehicle.h deleted file mode 100644 index c80aec3ddf..0000000000 --- a/src/vehicle.h +++ /dev/null @@ -1,77 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014 Ted John - * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. - * - * This file is part of OpenRCT2. - * - * OpenRCT2 is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *****************************************************************************/ - -#ifndef _VEHICLE_H_ -#define _VEHICLE_H_ - -#include "rct2.h" - -typedef union { - struct { - uint16 width; - uint16 height; - }; - uint32 both; -} rct_widthheight; - -typedef struct { - uint8 sprite_identifier; // 0x00 - uint8 pad_01[0x03]; - uint16 next; // 0x04 - uint16 previous; // 0x06 - uint8 linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_... - uint8 pad_09; - uint16 sprite_index; // 0x0A - uint8 pad_0C[2]; - sint16 x; // 0x0E - sint16 y; // 0x10 - sint16 z; // 0x12 - uint8 pad_14[0x02]; - rct_widthheight var_16; - rct_widthheight view; // 0x1A - uint16 var_1E; - uint8 pad_20[0x08]; - uint32 var_28; - uint8 pad_2C[0x04]; - uint8 ride; // 0x30 - uint8 var_31; - uint8 pad_32[0x0C]; - uint16 next_vehicle_on_train; // 0x3E - uint8 pad_40[0x08]; - uint16 var_48; - uint8 pad_4A[0x06]; - uint8 var_50; - uint8 var_51; - uint8 pad_52[0x2E]; - uint8 var_BB; - uint8 var_BC; - uint8 var_BD; - uint8 pad_BE[0x0E]; - uint8 var_CC; - uint8 pad_CD[0x09]; - uint8 var_D6; -} rct_vehicle; - -void vehicle_update_all(); - -/** Helper macro until rides are stored in this module. */ -#define GET_VEHICLE(sprite_index) &(g_sprite_list[sprite_index].vehicle) - -#endif \ No newline at end of file diff --git a/src/window_peep.c b/src/window_peep.c deleted file mode 100644 index a85331101c..0000000000 --- a/src/window_peep.c +++ /dev/null @@ -1,924 +0,0 @@ -/***************************************************************************** -* Copyright (c) 2014 Ted John, Duncan Frost -* OpenRCT2, an open source clone of Roller Coaster Tycoon 2. -* -* This file is part of OpenRCT2. -* -* OpenRCT2 is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. - -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. - -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*****************************************************************************/ - -#include "addresses.h" -#include "game.h" -#include "map.h" -#include "ride.h" -#include "peep.h" -#include "string_ids.h" -#include "sprite.h" -#include "sprites.h" -#include "viewport.h" -#include "widget.h" -#include "window.h" -#include "window_dropdown.h" - -enum WINDOW_PEEP_PAGE { - WINDOW_PEEP_OVERVIEW, - WINDOW_PEEP_STATS, - WINDOW_PEEP_RIDES, - WINDOW_PEEP_FINANCE, - WINDOW_PEEP_THOUGHTS, - WINDOW_PEEP_INVENTORY -}; - -enum WINDOW_PEEP_WIDGET_IDX { - WIDX_BACKGROUND, - WIDX_TITLE, - WIDX_CLOSE, - WIDX_PAGE_BACKGROUND, - WIDX_TAB_1, - WIDX_TAB_2, - WIDX_TAB_3, - WIDX_TAB_4, - WIDX_TAB_5, - WIDX_TAB_6, - - WIDX_MARQUEE = 10, - WIDX_VIEWPORT, - WIDX_ACTION_LBL, - WIDX_PICKUP, - WIDX_RENAME, - WIDX_LOCATE, - WIDX_TRACK, - - WIDX_RIDE_SCROLL = 10 -}; - -void window_peep_emptysub(){}; - -rct_widget window_peep_overview_widgets[] = { - { WWT_FRAME, 0, 0, 191, 0, 156, 0x0FFFFFFFF, STR_NONE }, // Panel / Background - { WWT_CAPTION, 0, 1, 190, 1, 14, 865, STR_WINDOW_TITLE_TIP }, // Title - { WWT_CLOSEBOX, 0, 179, 189, 2, 13, 824, STR_CLOSE_WINDOW_TIP }, // Close x button - { WWT_RESIZE, 1, 1, 191, 43, 156, 0x0FFFFFFFF, STR_NONE }, // Resize - { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, 1938 }, // Tab 1 - { WWT_TAB, 1, 73, 64, 17, 43, 0x2000144E, 1940}, // Tab 2 - { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, 1941}, // Tab 3 - { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, 1942}, // Tab 4 - { WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, 1943}, // Tab 5 - { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, 1944}, // Tab 6 - { WWT_12, 1, 3, 166, 45, 56, 0x0FFFFFFFF, STR_NONE}, // Label Thought marquee - { WWT_VIEWPORT, 1, 3, 166, 57, 143, 0x0FFFFFFFF, STR_NONE }, // Viewport - { WWT_12, 1, 3, 166, 144, 154, 0x0FFFFFFFF, STR_NONE}, // Label Action - { WWT_FLATBTN, 1, 167, 190, 45, 68, 0x1436, 1706}, // Pickup Button - { WWT_FLATBTN, 1, 167, 190, 69, 92, SPR_RENAME, 1055}, // Rename Button - { WWT_FLATBTN, 1, 167, 190, 93, 116, SPR_LOCATE, STR_LOCATE_SUBJECT_TIP},// Locate Button - { WWT_FLATBTN, 1, 167, 190, 117, 140, SPR_TRACK_PEEP, 1930}, // Track Button - { WIDGETS_END }, -}; - -rct_widget window_peep_stats_widgets[] = { - {WWT_FRAME, 0, 0, 191, 0, 156, -1, STR_NONE}, - {WWT_CAPTION, 0, 1, 190, 1, 14, 865, STR_WINDOW_TITLE_TIP}, - {WWT_CLOSEBOX, 0, 179, 189, 2, 13, 824, STR_CLOSE_WINDOW_TIP}, - {WWT_RESIZE, 1, 0, 191, 43, 156, -1, STR_NONE}, - {WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, 1938}, - {WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, 1940}, - {WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, 1941}, - {WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, 1942}, - {WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, 1943}, - {WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, 1944}, - {WIDGETS_END}, -}; - -rct_widget window_peep_rides_widgets[] = { - {WWT_FRAME, 0, 0, 191, 0, 156, -1, STR_NONE}, - {WWT_CAPTION, 0, 1, 190, 1, 14, 865, STR_WINDOW_TITLE_TIP}, - {WWT_CLOSEBOX, 0, 179, 189, 2, 13, 824, STR_CLOSE_WINDOW_TIP}, - {WWT_RESIZE, 1, 0, 191, 43, 156, -1, STR_NONE}, - {WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, 1938}, - {WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, 1940}, - {WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, 1941}, - {WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, 1942}, - {WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, 1943}, - {WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, 1944}, - {WWT_SCROLL, 1, 3, 188, 57, 143, 2, STR_NONE}, - {WIDGETS_END}, -}; - -rct_widget window_peep_finance_widgets[] = { - {WWT_FRAME, 0, 0, 191, 0, 156, -1, STR_NONE}, - {WWT_CAPTION, 0, 1, 190, 1, 14, 865, STR_WINDOW_TITLE_TIP}, - {WWT_CLOSEBOX, 0, 179, 189, 2, 13, 824, STR_CLOSE_WINDOW_TIP}, - {WWT_RESIZE, 1, 0, 191, 43, 156, -1, STR_NONE}, - {WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, 1938}, - {WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, 1940}, - {WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, 1941}, - {WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, 1942}, - {WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, 1943}, - {WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, 1944}, - {WIDGETS_END}, -}; - -rct_widget window_peep_thoughts_widgets[] = { - {WWT_FRAME, 0, 0, 191, 0, 156, -1, STR_NONE}, - {WWT_CAPTION, 0, 1, 190, 1, 14, 865, STR_WINDOW_TITLE_TIP}, - {WWT_CLOSEBOX, 0, 179, 189, 2, 13, 824, STR_CLOSE_WINDOW_TIP}, - {WWT_RESIZE, 1, 0, 191, 43, 156, -1, STR_NONE}, - {WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, 1938}, - {WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, 1940}, - {WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, 1941}, - {WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, 1942}, - {WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, 1943}, - {WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, 1944}, - {WIDGETS_END}, -}; - -rct_widget window_peep_inventory_widgets[] = { - {WWT_FRAME, 0, 0, 191, 0, 156, -1, STR_NONE}, - {WWT_CAPTION, 0, 1, 190, 1, 14, 865, STR_WINDOW_TITLE_TIP}, - {WWT_CLOSEBOX, 0, 179, 189, 2, 13, 824, STR_CLOSE_WINDOW_TIP}, - {WWT_RESIZE, 1, 0, 191, 43, 156, -1, STR_NONE}, - {WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, 1938}, - {WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, 1940}, - {WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, 1941}, - {WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, 1942}, - {WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, 1943}, - {WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, 1944}, - {WIDGETS_END}, -}; - -//0x981D0C -rct_widget *window_peep_page_widgets[] = { - window_peep_overview_widgets, - window_peep_stats_widgets, - window_peep_rides_widgets, - window_peep_finance_widgets, - window_peep_thoughts_widgets, - window_peep_inventory_widgets -}; - -void window_peep_set_page(rct_window* w, int page); -void window_peep_disable_widgets(rct_window* w); -void window_peep_viewport_init(rct_window* w); - -void window_peep_close(); -void window_peep_resize(); -void window_peep_overview_mouse_up(); -void window_peep_overview_paint(); -void window_peep_overview_invalidate(); -void window_peep_overview_viewport_init_wrapper(); - -static void* window_peep_overview_events[] = { - window_peep_close, - window_peep_overview_mouse_up, - window_peep_resize, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - (void*)0x696F45, - window_peep_emptysub, - window_peep_emptysub, - (void*)0x696A5F, - (void*)0x696A54, - window_peep_emptysub, - window_peep_emptysub, - (void*)0x696A49, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - (void*)0x696A6A, - window_peep_overview_viewport_init_wrapper, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_overview_invalidate, //Invalidate - window_peep_overview_paint, //Paint - window_peep_emptysub -}; - -static void* window_peep_stats_events[] = { - window_peep_emptysub, - (void*) 0x0069744F, //mouse_up - (void*) 0x00697488, //resize - window_peep_emptysub, - window_peep_emptysub, - (void*) 0x006974ED, - (void*) 0x0069746A, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - (void*) 0x0069707D, //invalidate - (void*) 0x0069711D, //paint - window_peep_emptysub -}; - -static void* window_peep_rides_events[] = { - window_peep_emptysub, - (void*) 0x00697795, //mouse_up - (void*) 0x006978F4, //resize - window_peep_emptysub, - window_peep_emptysub, - (void*) 0x00697959, - (void*) 0x006977B0, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - (void*) 0x0069784E, - (void*) 0x006978CC, - window_peep_emptysub, - (void*) 0x0069789C, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - (void*) 0x00697844, - window_peep_emptysub, - window_peep_emptysub, - (void*) 0x0069757A, //invalidate - (void*) 0x00697637, //paint - (void*) 0x006976FC -}; - -static void* window_peep_finance_events[] = { - window_peep_emptysub, - (void*) 0x00697BDD, //mouse_up - (void*) 0x00697C16, //resize - window_peep_emptysub, - window_peep_emptysub, - (void*) 0x00697C7B, - (void*) 0x00697BF8, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - (void*) 0x00697968, //invalidate - (void*) 0x00697A08, //paint - window_peep_emptysub -}; - -static void* window_peep_thoughts_events[] = { - window_peep_emptysub, - (void*) 0x00697E18, //mouse_up - (void*) 0x00697E33, //resize - window_peep_emptysub, - window_peep_emptysub, - (void*) 0x00697ED2, - (void*) 0x00697EB4, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - (void*) 0x00697C8A, //invalidate - (void*) 0x00697D2A, //paint - window_peep_emptysub -}; - -static void* window_peep_inventory_events[] = { - window_peep_emptysub, - (void*) 0x00698279, //mouse_up - (void*) 0x00698294, //resize - window_peep_emptysub, - window_peep_emptysub, - (void*) 0x00698333, - (void*) 0x00698315, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - window_peep_emptysub, - (void*) 0x00697EE1, //invalidate - (void*) 0x00697F81, //paint - window_peep_emptysub -}; - -//0x981D24 -void* window_peep_page_events[] = { - window_peep_overview_events, - window_peep_stats_events, - window_peep_rides_events, - window_peep_finance_events, - window_peep_thoughts_events, - window_peep_inventory_events -}; - -//0x981D3C -uint32 window_peep_page_enabled_widgets[] = { - (1 << WIDX_CLOSE) | - (1 << WIDX_TAB_1) | - (1 << WIDX_TAB_2) | - (1 << WIDX_TAB_3) | - (1 << WIDX_TAB_4) | - (1 << WIDX_TAB_5) | - (1 << WIDX_TAB_6) | - (1 << WIDX_RENAME)| - (1 << WIDX_PICKUP)| - (1 << WIDX_LOCATE)| - (1 << WIDX_TRACK), - - (1 << WIDX_CLOSE) | - (1 << WIDX_TAB_1) | - (1 << WIDX_TAB_2) | - (1 << WIDX_TAB_3) | - (1 << WIDX_TAB_4) | - (1 << WIDX_TAB_5) | - (1 << WIDX_TAB_6), - - (1 << WIDX_CLOSE) | - (1 << WIDX_TAB_1) | - (1 << WIDX_TAB_2) | - (1 << WIDX_TAB_3) | - (1 << WIDX_TAB_4) | - (1 << WIDX_TAB_5) | - (1 << WIDX_TAB_6) | - (1 << WIDX_RIDE_SCROLL), - - (1 << WIDX_CLOSE) | - (1 << WIDX_TAB_1) | - (1 << WIDX_TAB_2) | - (1 << WIDX_TAB_3) | - (1 << WIDX_TAB_4) | - (1 << WIDX_TAB_5) | - (1 << WIDX_TAB_6), - - (1 << WIDX_CLOSE) | - (1 << WIDX_TAB_1) | - (1 << WIDX_TAB_2) | - (1 << WIDX_TAB_3) | - (1 << WIDX_TAB_4) | - (1 << WIDX_TAB_5) | - (1 << WIDX_TAB_6), - - (1 << WIDX_CLOSE) | - (1 << WIDX_TAB_1) | - (1 << WIDX_TAB_2) | - (1 << WIDX_TAB_3) | - (1 << WIDX_TAB_4) | - (1 << WIDX_TAB_5) | - (1 << WIDX_TAB_6) -}; - -/** - * rct2: 0x006989E9 - * - */ -void window_peep_open(rct_peep* peep){ - - if (peep->type == PEEP_TYPE_STAFF){ - window_staff_peep_open(peep); - return; - } - - rct_window* window; - - window = window_bring_to_front_by_id(WC_PEEP, peep->sprite_index); - if (window == NULL){ - window = window_create_auto_pos(192, 157, (uint32*)window_peep_overview_events, WC_PEEP, 0); - window->widgets = window_peep_overview_widgets; - window->enabled_widgets = window_peep_page_enabled_widgets[0]; - window->number = peep->sprite_index; - window->page = 0; - window->viewport_focus_coordinates.y = 0; - window->frame_no = 0; - window->list_information_type = 0; - window->var_492 = 0; - window->var_494 = 0; - window_peep_disable_widgets(window); - window->min_width = 192; - window->min_height = 157; - window->max_width = 500; - window->max_height = 450; - window->flags = 1 << 8; - window->no_list_items = 0; - window->selected_list_item = -1; - window->colours[0] = 1; - window->colours[1] = 15; - window->colours[2] = 15; - window->viewport_focus_coordinates.y = -1; - } - - window->page = 0; - window_invalidate(window); - - window->widgets = window_peep_page_widgets[WINDOW_PEEP_OVERVIEW]; - window->enabled_widgets = window_peep_page_enabled_widgets[WINDOW_PEEP_OVERVIEW]; - window->var_020 = RCT2_GLOBAL(0x981D54,uint32); - window->event_handlers = window_peep_page_events[WINDOW_PEEP_OVERVIEW]; - window->pressed_widgets = 0; - - window_peep_disable_widgets(window); - window_init_scroll_widgets(window); - window_peep_viewport_init(window); -} - -/* rct2: 0x006987A6 - * Disables the finance tab when no money. - * Disables peep pickup when in certain no pickup states. - */ -void window_peep_disable_widgets(rct_window* w){ - rct_peep* peep = &g_sprite_list[w->number].peep; - uint64 disabled_widgets = 0; - - if (peep_can_be_picked_up(peep)){ - if (w->disabled_widgets & (1 << WIDX_PICKUP)) - window_invalidate(w); - } - else{ - disabled_widgets = (1 << WIDX_PICKUP); - if (!(w->disabled_widgets & (1 << WIDX_PICKUP))) - window_invalidate(w); - } - if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY){ - disabled_widgets |= (1 << WIDX_TAB_4); //Disable finance tab if no money - } - w->disabled_widgets = disabled_widgets; -} - -/* rct2: 0x00696A75 */ -void window_peep_close(){ - rct_window* w; - - window_get_register(w); - - if (RCT2_GLOBAL(0x9DE518,uint32) & (1<<3)){ - if (w->classification == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS,rct_windowclass) && - w->number == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER,rct_windownumber)) - tool_cancel(); - } -} - -/* rct2: 0x00696FBE */ -void window_peep_resize(){ - rct_window* w; - - window_get_register(w); - - window_peep_disable_widgets(w); - RCT2_CALLPROC_EBPSAFE(w->event_handlers[WE_INVALIDATE]); - - window_invalidate_by_id(0xA97, w->number); - - window_set_resize(w, 192, 159, 500, 450); - - rct_viewport* view = w->viewport; - - if (view){ - if ((w->width - 30) == view->width){ - if ((w->height - 72) == view->height){ - window_peep_viewport_init(w); - return; - } - } - uint8 zoom_amount = 1 << view->zoom; - view->width = w->width - 30; - view->height = w->height - 72; - view->view_width = view->width / zoom_amount; - view->view_height = view->height / zoom_amount; - } - window_peep_viewport_init(w); -} - -/* rct2: 0x00696A06 */ -void window_peep_overview_mouse_up(){ - short widgetIndex; - rct_window* w; - window_widget_get_registers(w, widgetIndex); - rct_peep* peep = GET_PEEP(w->number); - - switch(widgetIndex){ - case WIDX_CLOSE: - window_close(w); - break; - case WIDX_TAB_1: - case WIDX_TAB_2: - case WIDX_TAB_3: - case WIDX_TAB_4: - case WIDX_TAB_5: - case WIDX_TAB_6: - window_peep_set_page(w, widgetIndex - WIDX_TAB_1); - break; - case WIDX_PICKUP: - if (!peep_can_be_picked_up(peep)) { - return; - } - if (tool_set(w, widgetIndex, 7)) { - return; - } - - w->var_48C = peep->sprite_identifier; - - RCT2_CALLPROC_X(0x0069A512, 0, 0, 0, 0, (int)peep, 0, 0); - RCT2_CALLPROC_X(0x006EC473, 0, 0, 0, 0, (int)peep, 0, 0); - - RCT2_CALLPROC_X(0x0069E9D3, 0x8000, 0, peep->y, peep->z, (int)peep, 0, 0); - RCT2_CALLPROC_X(0x0069A409, 0, 0, 0, 0, (int)peep, 0, 0); - peep->state = 9; - peep->pad_2C = 0; - RCT2_CALLPROC_X(0x0069A42F, 0, 0, 0, 0, (int)peep, 0, 0); - break; - case WIDX_RENAME: - window_show_textinput(w, (int)widgetIndex, 0x5AC, 0x5AD, peep->name_string_idx); - break; - case WIDX_LOCATE: - window_scroll_to_viewport(w); - break; - case WIDX_TRACK: - g_sprite_list[w->number].peep.flags ^= PEEP_FLAGS_TRACKING; - break; - } -} - -void window_peep_set_page(rct_window* w, int page){ - if (RCT2_GLOBAL(0x9DE518,uint32) & (1 << 3)) - { - if(w->number == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber) && - w->classification == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass)) - tool_cancel(); - - } - int listen = 0; - if ( page == WINDOW_PEEP_OVERVIEW && w->page==WINDOW_PEEP_OVERVIEW && w->viewport){ - if(!(w->viewport->flags & VIEWPORT_FLAG_SOUND_ON)) - listen = 1; - } - - - w->page = page; - w->frame_no = 0; - w->no_list_items = 0; - w->selected_list_item = -1; - - rct_viewport* viewport = w->viewport; - w->viewport = 0; - if (viewport){ - viewport->width = 0; - } - - w->enabled_widgets = window_peep_page_enabled_widgets[page]; - w->var_020 = RCT2_ADDRESS(0x981D54,uint32)[page]; - w->event_handlers = window_peep_page_events[page]; - w->pressed_widgets = 0; - w->widgets = window_peep_page_widgets[page]; - window_peep_disable_widgets(w); - window_invalidate(w); - - RCT2_CALLPROC_X(w->event_handlers[WE_RESIZE], 0, 0, 0, 0, (int)w, 0, 0); - RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); - - window_init_scroll_widgets(w); - window_invalidate(w); - - if (listen && w->viewport) w->viewport->flags |= VIEWPORT_FLAG_SOUND_ON; -} - -void window_peep_overview_viewport_init_wrapper(){ - rct_window* w; - window_get_register(w); - - window_peep_viewport_init(w); -} - -/* rct2: 0x0069883C */ -void window_peep_viewport_init(rct_window* w){ - if (w->page != WINDOW_PEEP_OVERVIEW) return; - - union{ - sprite_focus sprite; - coordinate_focus coordinate; - } focus; //The focus will be either a sprite or a coordinate. - - focus.sprite.sprite_id = w->number; - - rct_peep* peep = GET_PEEP(w->number); - - if (peep->state == PEEP_STATE_PICKED){ - focus.sprite.sprite_id = -1; - } - else{ - uint8 final_check = 1; - if (peep->state == PEEP_STATE_ON_RIDE - || peep->state == PEEP_STATE_ENTERING_RIDE - || (peep->state == PEEP_STATE_LEAVING_RIDE && peep->x == SPRITE_LOCATION_NULL)){ - - rct_ride* ride = &(RCT2_ADDRESS(RCT2_ADDRESS_RIDE_LIST, rct_ride)[peep->current_ride]); - if (ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK){ - rct_vehicle* train = GET_VEHICLE(ride->train_car_map[peep->current_train]); - int car = peep->current_car; - - for (; car != 0; car--){ - train = GET_VEHICLE(train->next_vehicle_on_train); - } - - focus.sprite.sprite_id = train->sprite_index; - final_check = 0; - } - } - if (peep->x == SPRITE_LOCATION_NULL && final_check){ - rct_ride* ride = &(RCT2_ADDRESS(RCT2_ADDRESS_RIDE_LIST, rct_ride)[peep->current_ride]); - int x = ride->overall_view & 0xFF * 32 + 16; - int y = (ride->overall_view >> 8) * 32 + 16; - int height = map_element_height(x, y); - height += 32; - focus.coordinate.x = x; - focus.coordinate.y = y; - focus.coordinate.z = height; - focus.sprite.type |= VIEWPORT_FOCUS_TYPE_COORDINATE; - } - else{ - focus.sprite.type |= VIEWPORT_FOCUS_TYPE_SPRITE | VIEWPORT_FOCUS_TYPE_COORDINATE; - focus.sprite.pad_486 &= 0xFFFF; - } - focus.coordinate.rotation = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8); - } - - uint16 viewport_flags; - - if (w->viewport){ - //Check all combos, for now skipping y and rot - if (focus.coordinate.x == w->viewport_focus_coordinates.x && - focus.coordinate.y == w->viewport_focus_coordinates.y && - focus.coordinate.z == w->viewport_focus_coordinates.z && - focus.coordinate.rotation == w->viewport_focus_coordinates.rotation) - return; - - viewport_flags = w->viewport->flags; - w->viewport->width = 0; - w->viewport = 0; - - viewport_update_pointers(); - } - else{ - viewport_flags = 0; - if (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) & 0x1) - viewport_flags |= VIEWPORT_FLAG_GRIDLINES; - } - - RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); - - w->viewport_focus_coordinates.x = focus.coordinate.x; - w->viewport_focus_coordinates.y = focus.coordinate.y; - w->viewport_focus_coordinates.z = focus.coordinate.z; - w->viewport_focus_coordinates.rotation = focus.coordinate.rotation; - - if (peep->state != PEEP_STATE_PICKED){ - if (!(w->viewport)){ - rct_widget* view_widget = &w->widgets[WIDX_VIEWPORT]; - - int x = view_widget->left + 1 + w->x; - int y = view_widget->top + 1 + w->y; - int width = view_widget->right - view_widget->left - 1; - int height = view_widget->bottom - view_widget->top - 1; - - viewport_create(w, x, y, width, height, 0, focus.coordinate.x, focus.coordinate.y, focus.coordinate.z, focus.sprite.type & VIEWPORT_FOCUS_TYPE_MASK, focus.sprite.sprite_id); - w->flags |= WF_2; - window_invalidate(w); - } - } - - if (w->viewport) - w->viewport->flags = viewport_flags; - window_invalidate(w); -} - -/* rct2: 0x696887 */ -void window_peep_overview_paint(){ - rct_window *w; - rct_drawpixelinfo *dpi; - //rct_widget *labelWidget; - - window_paint_get_registers(w, dpi); - RCT2_CALLPROC_X(0x696887, 0, 0, 0, 0, (int)w, (int)dpi, 0); - return; - - window_draw_widgets(w, dpi); - //6983dd - //698597 - //6985d8 - //69861f - //69869b - //698661 - - // Draw the viewport no sound sprite - if (w->viewport){ - window_draw_viewport(dpi, w); - rct_viewport* viewport = w->viewport; - if (viewport->flags & VIEWPORT_FLAG_SOUND_ON){ - gfx_draw_sprite(dpi, SPR_HEARING_VIEWPORT, w->x + 2, w->y + 2, 0); - } - } - - // Draw the centered label - uint32 argument1, argument2; - rct_peep* peep = GET_PEEP(w->number); - get_arguments_from_action(peep, &argument1, &argument2); - RCT2_GLOBAL(0x13CE952, uint32) = argument1; - RCT2_GLOBAL(0x13CE952 + 4, uint32) = argument2; - rct_widget* widget = &w->widgets[WIDX_ACTION_LBL]; - int x = (widget->left + widget->right) / 2 + w->x; - int y = w->y + widget->top - 1; - int width = widget->right - widget->left; - gfx_draw_string_centred_clipped(dpi, 1191, (void*)0x13CE952, 0, x, y, width); - - // Draw the marquee thought - widget = &w->widgets[WIDX_MARQUEE]; - width = widget->right - widget->left - 3; - int left = widget->left + 2 + w->x; - int top = widget->top + w->y; - int height = widget->bottom - widget->top; - rct_drawpixelinfo* dpi_marquee = clip_drawpixelinfo(dpi, left, width, top, height); - - if (!dpi_marquee)return; - int i = 0; - for (; i < PEEP_MAX_THOUGHTS; ++i){ - if (peep->thoughts[i].type == PEEP_THOUGHT_TYPE_NONE){ - w->list_information_type = 0; - return; - } - if (peep->thoughts[i].var_2 == 1){ // If a fresh thought - break; - } - } - if (i == PEEP_MAX_THOUGHTS){ - w->list_information_type = 0; - return; - } - - get_arguments_from_thought(peep->thoughts[i], &argument1, &argument2); - - RCT2_GLOBAL(0x13CE952, uint32) = argument1; - RCT2_GLOBAL(0x13CE952 + 4, uint32) = argument2; - RCT2_GLOBAL(0x13CE952 + 8, uint16) = 0; - - x = widget->right - widget->left - w->list_information_type; - gfx_draw_string_left(dpi_marquee, 1193, (void*)0x13CE952, 0, x, 0); -} - -/* rct2: 0x696749*/ -void window_peep_overview_invalidate(){ - rct_window* w; - window_get_register(w); - - if (window_peep_page_widgets[w->page] != w->widgets){ - w->widgets = window_peep_page_widgets[w->page]; - window_init_scroll_widgets(w); - } - - w->pressed_widgets &= ~(WIDX_TAB_1 | WIDX_TAB_2 |WIDX_TAB_3 |WIDX_TAB_4 |WIDX_TAB_5 |WIDX_TAB_6); - w->pressed_widgets |= 1ULL << (w->page + WIDX_TAB_1); - - rct_peep* peep = GET_PEEP(w->number); - RCT2_GLOBAL(0x13CE952,uint16) = peep->name_string_idx; - RCT2_GLOBAL(0x13CE954,uint32) = peep->id; - - w->pressed_widgets &= ~(1<flags & 0x8){ - w->pressed_widgets |= (1<width - 1; - window_peep_overview_widgets[WIDX_BACKGROUND].bottom = w->height - 1; - - window_peep_overview_widgets[WIDX_PAGE_BACKGROUND].right =w->width - 1; - window_peep_overview_widgets[WIDX_PAGE_BACKGROUND].bottom = w->height - 1; - - window_peep_overview_widgets[WIDX_TITLE].right = w->width - 2; - - window_peep_overview_widgets[WIDX_CLOSE].left = w->width - 13; - window_peep_overview_widgets[WIDX_CLOSE].right = w->width - 3; - - window_peep_overview_widgets[WIDX_VIEWPORT].right = w->width - 26; - window_peep_overview_widgets[WIDX_VIEWPORT].bottom = w->height - 14; - - window_peep_overview_widgets[WIDX_ACTION_LBL].top = w->height - 12; - window_peep_overview_widgets[WIDX_ACTION_LBL].bottom = w->height - 3; - window_peep_overview_widgets[WIDX_ACTION_LBL].right = w->width - 24; - - window_peep_overview_widgets[WIDX_MARQUEE].right = w->width - 24; - - window_peep_overview_widgets[WIDX_PICKUP].right = w->width - 2; - window_peep_overview_widgets[WIDX_RENAME].right = w->width - 2; - window_peep_overview_widgets[WIDX_LOCATE].right = w->width - 2; - window_peep_overview_widgets[WIDX_TRACK].right = w->width - 2; - - window_peep_overview_widgets[WIDX_PICKUP].left = w->width - 25; - window_peep_overview_widgets[WIDX_RENAME].left = w->width - 25; - window_peep_overview_widgets[WIDX_LOCATE].left = w->width - 25; - window_peep_overview_widgets[WIDX_TRACK].left = w->width - 25; - - window_align_tabs(w, WIDX_TAB_1, WIDX_TAB_6); -} - -void window_peep_overview_tab_paint( rct_window* w, rct_drawpixelinfo* dpi){ - - if ( w->disabled_widgets & (1ULL<widgets[WIDX_TAB_1].left + 1 + w->x; - //cx - int y = w->widgets[WIDX_TAB_1].top + 1 + w->y; - //bx - int width = w->widgets[WIDX_TAB_1].right - 1 - w->widgets[WIDX_TAB_1].left; - //dx - int height = w->widgets[WIDX_TAB_1].bottom - 1 - w->widgets[WIDX_TAB_1].top; - - if (w->page == WINDOW_PEEP_OVERVIEW){ - height++; - } - - rct_drawpixelinfo* cliped_dpi = clip_drawpixelinfo( dpi, x, width, y, height ); - - if (!cliped_dpi) return; - - int cx = 14; - int dx = 20; - - //ebp - rct_peep* peep = GET_PEEP(w->number); - - - if (peep->type == 1 && peep->staff_type == 3) - dx++; - int eax = RCT2_GLOBAL(peep->sprite_type*8 + 0x982708, uint32); - int ebx = *(uint32*)eax; - ebx++; - eax = 0; - - if (w->page == WINDOW_PEEP_OVERVIEW){ - int ax = *((uint16*)w + 496 / 2); - ax &= ~((1<<0)|(1<<1)); - } - ebx += eax; - //698474 -} diff --git a/src/window_ride.c b/src/window_ride.c deleted file mode 100644 index 66b9e2a23b..0000000000 --- a/src/window_ride.c +++ /dev/null @@ -1,154 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014 Ted John - * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. - * - * This file is part of OpenRCT2. - * - * OpenRCT2 is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *****************************************************************************/ - -#include -#include "addresses.h" -#include "game.h" -#include "ride.h" -#include "string_ids.h" -#include "sprite.h" -#include "sprites.h" -#include "widget.h" -#include "window.h" -#include "window_dropdown.h" - -#pragma region Widgets - -static rct_widget *window_ride_page_widgets[] = { - (rct_widget*)0x009ADC34, - (rct_widget*)0x009ADDA8, - (rct_widget*)0x009ADEFC, - (rct_widget*)0x009AE190, - (rct_widget*)0x009AE2A4, - (rct_widget*)0x009AE4C8, - (rct_widget*)0x009AE5DC, - (rct_widget*)0x009AE710, - (rct_widget*)0x009AE844, - (rct_widget*)0x009AE9C8 -}; - -#pragma endregion - -#pragma region Events - -static uint32* window_ride_page_events[] = { - (uint32*)0x0098DFD4, - (uint32*)0x0098E204, - (uint32*)0x0098E0B4, - (uint32*)0x0098E124, - (uint32*)0x0098E044, - (uint32*)0x0098E194, - (uint32*)0x0098DE14, - (uint32*)0x0098DF64, - (uint32*)0x0098DEF4, - (uint32*)0x0098DE84 -}; - -#pragma endregion - -/** - * - * rct2: 0x006AEAB4 - */ -rct_window *window_ride_open(int rideIndex) -{ - rct_window *w; - - w = window_create_auto_pos(316, 180, window_ride_page_events[0], WC_RIDE, 0x400); - w->widgets = window_ride_page_widgets[0]; - w->enabled_widgets = 0x007DBFF4; - w->number = rideIndex; - - w->page = 0; - w->var_48C = 0; - w->frame_no = 0; - w->list_information_type = 0; - w->var_492 = 0; - w->var_494 = 0; - RCT2_CALLPROC_X(0x006AEB9F, 0, 0, 0, 0, (int)w, 0, 0); - w->min_width = 316; - w->min_height = 180; - w->max_width = 500; - w->max_height = 450; - w->flags |= WF_RESIZABLE; - w->colours[0] = 1; - w->colours[1] = 26; - w->colours[2] = 11; - - rct_ride *ride = &g_ride_list[rideIndex]; - uint8 *edx = (uint8*)0x009E32F8; - if (ride->type != RIDE_TYPE_NULL) { - int rideType = ride->type; - do { - edx++; - if (*(edx - 1) != 0xFF) - continue; - } while (rideType-- != 0); - } - - int eax, ebx = 0, ecx; - while (*edx != 0xFF) { - eax = *edx++; - ecx = eax >> 5; - eax &= 0x1F; - if (!(RCT2_ADDRESS(0x001357424, uint32)[ecx] & (1 << eax))) - continue; - ebx++; - } - RCT2_GLOBAL((int)w + 496, uint16) = ebx; - return w; -} - -/** - * - * rct2: 0x006ACC28 - */ -void window_ride_main_open(int rideIndex) -{ - rct_window *w; - - w = window_bring_to_front_by_id(WC_RIDE, rideIndex); - if (w == NULL) { - w = window_ride_open(rideIndex); - w->ride.var_482 = -1; - } - - if (RCT2_GLOBAL(0x009DE518, uint32) & (1 << 3)) { - if (w->classification == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) && - w->number == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber) - ) { - tool_cancel(); - } - } - - w->page = 0; - w->width = 316; - w->height = 180; - window_invalidate(w); - w->widgets = window_ride_page_widgets[0]; - w->enabled_widgets = 0x007DBFF4; - w->var_020 = 0; - w->event_handlers = window_ride_page_events[0]; - w->pressed_widgets = 0; - RCT2_CALLPROC_X(0x006AEB9F, 0, 0, 0, 0, (int)w, 0, 0); - window_init_scroll_widgets(w); - w->ride.var_480 = 0; - RCT2_CALLPROC_X(0x006AF994, 0, 0, 0, 0, (int)w, 0, 0); -} \ No newline at end of file diff --git a/src/window_about.c b/src/windows/about.c similarity index 96% rename from src/window_about.c rename to src/windows/about.c index 8cf3418380..22f8f1a7c0 100644 --- a/src/window_about.c +++ b/src/windows/about.c @@ -20,11 +20,11 @@ #include #include -#include "addresses.h" -#include "string_ids.h" -#include "sprites.h" -#include "widget.h" -#include "window.h" +#include "../addresses.h" +#include "../localisation/localisation.h" +#include "../sprites.h" +#include "../interface/widget.h" +#include "../interface/window.h" enum WINDOW_ABOUT_WIDGET_IDX { WIDX_BACKGROUND, @@ -125,10 +125,10 @@ static void window_about_mouseup() window_close(w); break; case WIDX_MUSIC_CREDITS: - RCT2_CALLPROC_EBPSAFE(0x0066D55B); + window_music_credits_open(); break; case WIDX_PUBLISHER_CREDITS: - RCT2_CALLPROC_EBPSAFE(0x0066D4EC); + window_publisher_credits_open(); break; } } diff --git a/src/window_banner.c b/src/windows/banner.c similarity index 97% rename from src/window_banner.c rename to src/windows/banner.c index 82c92d41e9..e95340b1f4 100644 --- a/src/window_banner.c +++ b/src/windows/banner.c @@ -19,12 +19,12 @@ *****************************************************************************/ #include -#include "addresses.h" -#include "config.h" -#include "string_ids.h" -#include "viewport.h" -#include "widget.h" -#include "window.h" +#include "../addresses.h" +#include "../config.h" +#include "../localisation/localisation.h" +#include "../interface/viewport.h" +#include "../interface/widget.h" +#include "../interface/window.h" enum WINDOW_BANNER_WIDGET_IDX { WIDX_BACKGROUND, diff --git a/src/window_cheats.c b/src/windows/cheats.c similarity index 95% rename from src/window_cheats.c rename to src/windows/cheats.c index 585388ee29..e20bdf1a3f 100644 --- a/src/window_cheats.c +++ b/src/windows/cheats.c @@ -21,18 +21,18 @@ #include #include #include -#include "addresses.h" -#include "park.h" -#include "peep.h" -#include "string_ids.h" -#include "sprite.h" -#include "sprites.h" -#include "widget.h" -#include "window.h" -#include "climate.h" -#include "ride.h" -#include "scenario.h" -#include "game.h" +#include "../addresses.h" +#include "../game.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../localisation/localisation.h" +#include "../peep/peep.h" +#include "../ride/ride.h" +#include "../scenario.h" +#include "../sprites.h" +#include "../world/climate.h" +#include "../world/park.h" +#include "../world/sprite.h" //#define WW 200 //#define WH 128 @@ -238,9 +238,9 @@ static void* window_cheats_page_events[] = { }; static uint32 window_cheats_page_enabled_widgets[] = { - (1 << WIDX_CLOSE) | (1 << WIDX_TAB_1) | (1 << WIDX_TAB_2) | (1 << WIDX_HIGH_MONEY) | (1 << WIDX_PARK_ENTRANCE_FEE), - (1 << WIDX_CLOSE) | (1 << WIDX_TAB_1) | (1 << WIDX_TAB_2) | (1 << WIDX_HAPPY_GUESTS) | (1 << WIDX_TRAM_GUESTS), - (1 << WIDX_CLOSE) | (1 << WIDX_TAB_1) | (1 << WIDX_TAB_2) | (1 << WIDX_FREEZE_CLIMATE) | (1 << WIDX_OPEN_CLOSE_PARK) | (1 << WIDX_DECREASE_GAME_SPEED) | (1 << WIDX_INCREASE_GAME_SPEED), + (1 << WIDX_CLOSE) | (1 << WIDX_TAB_1) | (1 << WIDX_TAB_2) | (1 << WIDX_TAB_3) | (1 << WIDX_HIGH_MONEY) | (1 << WIDX_PARK_ENTRANCE_FEE), + (1 << WIDX_CLOSE) | (1 << WIDX_TAB_1) | (1 << WIDX_TAB_2) | (1 << WIDX_TAB_3) | (1 << WIDX_HAPPY_GUESTS) | (1 << WIDX_TRAM_GUESTS), + (1 << WIDX_CLOSE) | (1 << WIDX_TAB_1) | (1 << WIDX_TAB_2) | (1 << WIDX_TAB_3) | (1 << WIDX_FREEZE_CLIMATE) | (1 << WIDX_OPEN_CLOSE_PARK) | (1 << WIDX_DECREASE_GAME_SPEED) | (1 << WIDX_INCREASE_GAME_SPEED), }; static void window_cheats_draw_tab_images(rct_drawpixelinfo *dpi, rct_window *w); diff --git a/src/window_clear_scenery.c b/src/windows/clear_scenery.c similarity index 97% rename from src/window_clear_scenery.c rename to src/windows/clear_scenery.c index df945f65d1..a507f3a313 100644 --- a/src/window_clear_scenery.c +++ b/src/windows/clear_scenery.c @@ -18,12 +18,12 @@ * along with this program. If not, see . *****************************************************************************/ -#include "addresses.h" -#include "map.h" -#include "string_ids.h" -#include "sprites.h" -#include "widget.h" -#include "window.h" +#include "../addresses.h" +#include "../world/map.h" +#include "../localisation/localisation.h" +#include "../sprites.h" +#include "../interface/widget.h" +#include "../interface/window.h" enum WINDOW_CLEAR_SCENERY_WIDGET_IDX { WIDX_BACKGROUND, diff --git a/src/window_dropdown.c b/src/windows/dropdown.c similarity index 80% rename from src/window_dropdown.c rename to src/windows/dropdown.c index c7298e9bf2..3408abd056 100644 --- a/src/window_dropdown.c +++ b/src/windows/dropdown.c @@ -20,13 +20,13 @@ #include #include -#include "addresses.h" -#include "scenario.h" -#include "string_ids.h" -#include "sprites.h" -#include "widget.h" -#include "window.h" -#include "window_dropdown.h" +#include "../addresses.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../localisation/localisation.h" +#include "../scenario.h" +#include "../sprites.h" +#include "dropdown.h" int gAppropriateImageDropdownItemsPerRow[] = { 1, 1, 1, 1, 2, 2, 3, 3, 4, @@ -44,13 +44,13 @@ static rct_widget window_dropdown_widgets[] = { { WIDGETS_END }, }; -int _dropdown_num_items; int _dropdown_num_columns; int _dropdown_num_rows; int _dropdown_item_width; int _dropdown_item_height; int _dropdown_highlighted_index; +int gDropdownNumItems; uint16 gDropdownItemsFormat[64]; sint64 gDropdownItemsArgs[64]; // Replaces 0x009DED38 @@ -149,7 +149,7 @@ void window_dropdown_show_text_custom_width(int x, int y, int extray, uint8 colo _dropdown_item_height = flags & 0x3F; // Set the widgets - _dropdown_num_items = num_items; + gDropdownNumItems = num_items; _dropdown_num_rows = num_items; window_dropdown_widgets[WIDX_BACKGROUND].bottom = _dropdown_item_height * num_items + 3; window_dropdown_widgets[WIDX_BACKGROUND].right = _dropdown_item_width + 3; @@ -175,7 +175,7 @@ void window_dropdown_show_text_custom_width(int x, int y, int extray, uint8 colo RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, sint8) = INPUT_STATE_DROPDOWN_ACTIVE; // Copy the following properties until all use of it is decompiled - RCT2_GLOBAL(0x009DEBA0, sint16) = _dropdown_num_items; + RCT2_GLOBAL(0x009DEBA0, sint16) = gDropdownNumItems; RCT2_GLOBAL(0x009DED44, sint32) = _dropdown_num_columns; RCT2_GLOBAL(0x009DED48, sint32) = _dropdown_num_rows; RCT2_GLOBAL(0x009DED40, sint32) = _dropdown_item_width; @@ -216,10 +216,10 @@ void window_dropdown_show_image(int x, int y, int extray, uint8 colour, uint8 fl // Set and calculate num items, rows and columns _dropdown_item_width = itemWidth; _dropdown_item_height = itemHeight; - _dropdown_num_items = numItems; + gDropdownNumItems = numItems; _dropdown_num_columns = numColumns; - _dropdown_num_rows = _dropdown_num_items / _dropdown_num_columns; - if (_dropdown_num_items % _dropdown_num_columns != 0) + _dropdown_num_rows = gDropdownNumItems / _dropdown_num_columns; + if (gDropdownNumItems % _dropdown_num_columns != 0) _dropdown_num_rows++; // Calculate position and size @@ -253,7 +253,7 @@ void window_dropdown_show_image(int x, int y, int extray, uint8 colour, uint8 fl RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, sint8) = INPUT_STATE_DROPDOWN_ACTIVE; // Copy the following properties until all use of it is decompiled - RCT2_GLOBAL(0x009DEBA0, sint16) = _dropdown_num_items; + RCT2_GLOBAL(0x009DEBA0, sint16) = gDropdownNumItems; RCT2_GLOBAL(0x009DED44, sint32) = _dropdown_num_columns; RCT2_GLOBAL(0x009DED48, sint32) = _dropdown_num_rows; RCT2_GLOBAL(0x009DED40, sint32) = _dropdown_item_width; @@ -278,7 +278,7 @@ static void window_dropdown_paint() _dropdown_highlighted_index = RCT2_GLOBAL(0x009DEBA2, sint16); { int i, cell_x, cell_y, l, t, r, b, item, image, colour; - for (i = 0; i < _dropdown_num_items; i++) { + for (i = 0; i < gDropdownNumItems; i++) { cell_x = i % _dropdown_num_columns; cell_y = i / _dropdown_num_columns; @@ -349,3 +349,82 @@ static void window_dropdown_paint() } } } + +/* New function based on 6e914e + * returns -1 if index is invalid + */ +int dropdown_index_from_point(int x, int y, rct_window* w){ + int top = y - w->y - 2; + if (top < 0) return -1; + + int left = x - w->x; + if (left >= w->width) return -1; + left -= 2; + if (left < 0) return -1; + + // _dropdown_item_width + int column_no = left / RCT2_GLOBAL(0x009DED40, sint32); + // _dropdown_no_columns + if (column_no >= RCT2_GLOBAL(0x009DED44, sint32)) return -1; + + // _dropdown_item_height + int row_no = top / RCT2_GLOBAL(0x9DED3C, uint8); + // _dropdown_no_rows + if (row_no >= RCT2_GLOBAL(0x009DED48, sint32)) return -1; + + // _dropdown_no_columns + int dropdown_index = row_no * RCT2_GLOBAL(0x009DED44, sint32) + column_no; + // _dropdown_no_items + if (dropdown_index >= RCT2_GLOBAL(0x009DEBA0, sint16)) return -1; + + return dropdown_index; +} + +void window_dropdown_show_colour(rct_window *w, rct_widget *widget, uint8 dropdownColour, uint8 selectedColour) +{ + window_dropdown_show_colour_available(w, widget, dropdownColour, selectedColour, 0xFFFFFFFF); +} + +/** + * rct2: 0x006ED43D + * al: dropdown colour + * ah: selected colour + * esi: window + * edi: widget + * ebp: unknown + */ +void window_dropdown_show_colour_available(rct_window *w, rct_widget *widget, uint8 dropdownColour, uint8 selectedColour, + uint32 availableColours) +{ + int i, numItems; + + // Count number of available colours + numItems = 0; + for (i = 0; i < 32; i++) + if (availableColours & (1 << i)) + numItems++; + + // Show dropdown + window_dropdown_show_image( + w->x + widget->left, + w->y + widget->top, + widget->bottom - widget->top + 1, + dropdownColour, + 0x80, + numItems, + 12, + 12, + gAppropriateImageDropdownItemsPerRow[numItems] + ); + + // Set items + for (i = 0; i < 32; i++) { + if (availableColours & (1 << i)) { + if (selectedColour == i) + RCT2_GLOBAL(0x009DEBA2, sint16) = i; + + gDropdownItemsFormat[i] = 0xFFFE; + gDropdownItemsArgs[i] = ((uint64)i << 32) | (0x20000000 | (i << 19) | 5059); + } + } +} diff --git a/src/window_dropdown.h b/src/windows/dropdown.h similarity index 81% rename from src/window_dropdown.h rename to src/windows/dropdown.h index b98598abac..76370cd212 100644 --- a/src/window_dropdown.h +++ b/src/windows/dropdown.h @@ -21,12 +21,13 @@ #ifndef _WINDOW_DROPDOWN_H_ #define _WINDOW_DROPDOWN_H_ -#include "rct2.h" +#include "../common.h" #define DROPDOWN_SEPARATOR 0 extern int gAppropriateImageDropdownItemsPerRow[]; +extern int gDropdownNumItems; extern uint16 gDropdownItemsFormat[64]; extern sint64 gDropdownItemsArgs[64]; extern uint32 gDropdownItemsChecked; @@ -35,5 +36,8 @@ void window_dropdown_show_text(int x, int y, int extray, uint8 colour, uint8 fla void window_dropdown_show_text_custom_width(int x, int y, int extray, uint8 colour, uint8 flags, int num_items, int width); void window_dropdown_show_image(int x, int y, int extray, uint8 colour, uint8 flags, int numItems, int itemWidth, int itemHeight, int numColumns); void window_dropdown_close(); +int dropdown_index_from_point(int x, int y, rct_window* w); +void window_dropdown_show_colour(rct_window *w, rct_widget *widget, uint8 dropdownColour, uint8 selectedColour); +void window_dropdown_show_colour_available(rct_window *w, rct_widget *widget, uint8 dropdownColour, uint8 selectedColour, uint32 availableColours); #endif \ No newline at end of file diff --git a/src/windows/error.c b/src/windows/error.c new file mode 100644 index 0000000000..8e4efb7d9e --- /dev/null +++ b/src/windows/error.c @@ -0,0 +1,202 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of OpenRCT2. + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#include "../addresses.h" +#include "../audio/audio.h" +#include "../localisation/localisation.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "error.h" + +enum { + WIDX_BACKGROUND +}; + +static rct_widget window_error_widgets[] = { + { WWT_IMGBTN, 0, 0, 199, 0, 41, 0xFFFFFFFF, STR_NONE }, + { WIDGETS_END } +}; + +static void window_error_emptysub() { } +static void window_error_unknown5(); +static void window_error_paint(); + +static void* window_error_events[] = { + (uint32*)window_error_emptysub, + (uint32*)window_error_emptysub, + (uint32*)window_error_emptysub, + (uint32*)window_error_emptysub, + (uint32*)window_error_emptysub, + (uint32*)window_error_unknown5, + (uint32*)window_error_emptysub, + (uint32*)window_error_emptysub, + (uint32*)window_error_emptysub, + (uint32*)window_error_emptysub, + (uint32*)window_error_emptysub, + (uint32*)window_error_emptysub, + (uint32*)window_error_emptysub, + (uint32*)window_error_emptysub, + (uint32*)window_error_emptysub, + (uint32*)window_error_emptysub, + (uint32*)window_error_emptysub, + (uint32*)window_error_emptysub, + (uint32*)window_error_emptysub, + (uint32*)window_error_emptysub, + (uint32*)window_error_emptysub, + (uint32*)window_error_emptysub, + (uint32*)window_error_emptysub, + (uint32*)window_error_emptysub, + (uint32*)window_error_emptysub, + (uint32*)window_error_emptysub, + (uint32*)window_error_paint, + (uint32*)window_error_emptysub +}; + +static char _window_error_text[512]; +static uint16 _window_error_num_lines; + +/** + * + * rct2: 0x006C23B1 + */ +int sub_6C23B1(char *text) +{ + int eax, ebx, ecx, edx, esi, edi, ebp; + esi = (int)text; + RCT2_CALLFUNC_X(0x006C23B1, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + return *((sint16*)&ecx); +} + +/** + * + * rct2: 0x0066792F + * + * bx: title + * dx: message + */ +void window_error_open(rct_string_id title, rct_string_id message) +{ + char *dst, *args; + int numLines, fontHeight, x, y, width, height, maxY; + rct_window *w; + + window_close_by_id(WC_ERROR, 0); + dst = _window_error_text; + args = (char*)0x0013CE952; + + // Format the title + *dst++ = FORMAT_BLACK; + if (title != (rct_string_id)STR_NONE) { + format_string(dst, title, args); + dst += get_string_length(dst); + } + + // Format the message + if (message != (rct_string_id)STR_NONE) { + *dst++ = FORMAT_NEWLINE; + format_string(dst, message, args); + dst += get_string_length(dst); + } + + // Check if there is any text to display + if (dst == _window_error_text + 1) + return; + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 224; + width = sub_6C23B1(_window_error_text); + width = min(196, width); + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 224; + gfx_wrap_string(_window_error_text, width + 1, &numLines, &fontHeight); + + _window_error_num_lines = numLines; + width = width + 3; + height = (numLines + 1) * 10 + 4; + + window_error_widgets[WIDX_BACKGROUND].right = width; + window_error_widgets[WIDX_BACKGROUND].bottom = height; + + x = RCT2_GLOBAL(0x0142406C, sint32) - (width / 2); + x = clamp(0, x, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16)); + + y = RCT2_GLOBAL(0x01424070, sint32) + 26; + y = max(22, y); + maxY = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16) - height; + if (y > maxY) { + y = y - height - 40; + y = min(y, maxY); + } + + w = window_create(x, y, width, height, (uint32*)window_error_events, WC_ERROR, WF_STICK_TO_FRONT | WF_TRANSPARENT | WF_RESIZABLE); + w->widgets = window_error_widgets; + w->error.var_480 = 0; + if (!(RCT2_GLOBAL(0x009A8C29, uint8) & 1)) + sound_play_panned(SOUND_ERROR, 0, w->x + (w->width / 2), 0, 0); +} + +/** + * + * rct2: 0x00667BFE + */ +static void window_error_unknown5() +{ + rct_window *w; + + window_get_register(w); + + w->error.var_480++; + if (w->error.var_480 >= 8) + window_close(w); +} + +/** + * + * rct2: 0x00667AA3 + */ +static void window_error_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + int t, l, r, b; + + window_paint_get_registers(w, dpi); + + l = w->x; + t = w->y; + r = w->x + w->width - 1; + b = w->y + w->height - 1; + + gfx_fill_rect(dpi, l + 1, t + 1, r - 1, b - 1, 0x200002D); + gfx_fill_rect(dpi, l, t, r, b, 0x200008B); + + gfx_fill_rect(dpi, l, t + 2, l, b - 2, 0x200002F); + gfx_fill_rect(dpi, r, t + 2, r, b - 2, 0x200002F); + gfx_fill_rect(dpi, l + 2, b, r - 2, b, 0x200002F); + gfx_fill_rect(dpi, l + 2, t, r - 2, t, 0x200002F); + + gfx_fill_rect(dpi, r + 1, t + 1, r + 1, t + 1, 0x200002F); + gfx_fill_rect(dpi, r - 1, t + 1, r - 1, t + 1, 0x200002F); + gfx_fill_rect(dpi, l + 1, b - 1, l + 1, b - 1, 0x200002F); + gfx_fill_rect(dpi, r - 1, b - 1, r - 1, b - 1, 0x200002F); + + l = w->x + (w->width + 1) / 2 - 1; + t = w->y + 1; + draw_string_centred_raw(dpi, l, t, _window_error_num_lines, _window_error_text); +} \ No newline at end of file diff --git a/src/window_error.h b/src/windows/error.h similarity index 91% rename from src/window_error.h rename to src/windows/error.h index 780dccad1a..3ddb36c1c9 100644 --- a/src/window_error.h +++ b/src/windows/error.h @@ -21,6 +21,8 @@ #ifndef _WINDOW_ERROR_H_ #define _WINDOW_ERROR_H_ -void window_error_open(int stringId, int edx); +#include "../common.h" + +void window_error_open(rct_string_id title, rct_string_id message); #endif \ No newline at end of file diff --git a/src/window_finances.c b/src/windows/finances.c similarity index 98% rename from src/window_finances.c rename to src/windows/finances.c index 56f7072898..cdbfbf7f50 100644 --- a/src/window_finances.c +++ b/src/windows/finances.c @@ -18,19 +18,20 @@ * along with this program. If not, see . *****************************************************************************/ -#include "addresses.h" -#include "date.h" -#include "finance.h" -#include "game.h" -#include "graph.h" -#include "marketing.h" -#include "ride.h" -#include "scenario.h" -#include "string_ids.h" -#include "sprites.h" -#include "widget.h" -#include "window.h" -#include "window_dropdown.h" +#include "../addresses.h" +#include "../game.h" +#include "../interface/graph.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../localisation/date.h" +#include "../localisation/localisation.h" +#include "../management/finance.h" +#include "../management/marketing.h" +#include "../management/research.h" +#include "../ride/ride.h" +#include "../scenario.h" +#include "../sprites.h" +#include "dropdown.h" enum { WINDOW_FINANCES_PAGE_SUMMARY, @@ -535,7 +536,7 @@ void window_finances_open() w->colours[0] = 1; w->colours[1] = 19; w->colours[2] = 19; - RCT2_CALLPROC_EBPSAFE(0x00684BAE); + research_update_uncompleted_types(); } w->page = 0; @@ -1434,7 +1435,7 @@ static void window_finances_research_invalidate() // Checkboxes int activeResearchTypes = RCT2_GLOBAL(RCT2_ADDRESS_ACTIVE_RESEARCH_TYPES, uint16); - int uncompletedResearchTypes = RCT2_GLOBAL(RCT2_ADDRESS_UNCOMPLETED_RESEARCH_TYPES, uint16); + int uncompletedResearchTypes = gResearchUncompletedCategories; for (int i = 0; i < 7; i++) { int mask = 1 << i; int widgetMask = 1 << (i + WIDX_TRANSPORT_RIDES); diff --git a/src/window_footpath.c b/src/windows/footpath.c similarity index 96% rename from src/window_footpath.c rename to src/windows/footpath.c index 1e70c75998..b09b37cee6 100644 --- a/src/window_footpath.c +++ b/src/windows/footpath.c @@ -19,16 +19,16 @@ *****************************************************************************/ #include -#include "addresses.h" -#include "audio.h" -#include "game.h" -#include "map.h" -#include "string_ids.h" -#include "sprites.h" -#include "viewport.h" -#include "widget.h" -#include "window.h" -#include "window_dropdown.h" +#include "../addresses.h" +#include "../audio/audio.h" +#include "../game.h" +#include "../world/map.h" +#include "../localisation/localisation.h" +#include "../sprites.h" +#include "../interface/viewport.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "dropdown.h" enum { PATH_CONSTRUCTION_MODE_LAND, @@ -391,7 +391,7 @@ static void window_footpath_toolupdate() if (widgetIndex == WIDX_CONSTRUCT_ON_LAND) { window_footpath_set_provisional_path_at_point(x, y); } else if (widgetIndex == WIDX_CONSTRUCT_BRIDGE_OR_TUNNEL) { - RCT2_CALLPROC_X(0x006A8388, 0, 0, 0, 0, (int)w, 0, 0); + RCT2_CALLPROC_X(0x006A8388, x, y, 0, 0, (int)w, 0, 0); } } @@ -615,16 +615,7 @@ static void window_footpath_set_provisional_path_at_point(int x, int y) RCT2_CALLPROC_EBPSAFE(0x0068AAE1); RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~4; - // Get map coordinates from point - int eax, ebx, ecx, edx, esi, edi, ebp; - eax = x; - ebx = y; - edx = -34; - RCT2_CALLFUNC_X(0x00685ADC, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - x = eax & 0xFFFF; - z = ebx & 0xFF; - y = ecx & 0xFFFF; - mapElement = (rct_map_element*)edx; + get_map_coordinates_from_pos(x, y, 0xFFDE, &x, &y, &z, &mapElement); if (z == 0) { RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~1; @@ -697,17 +688,7 @@ static void window_footpath_place_path_at_point(int x, int y) RCT2_CALLPROC_EBPSAFE(0x006A7831); - // Get map coordinates from point - int eax, ebx, ecx, edx, esi, edi, ebp; - eax = x; - ebx = y; - edx = -34; - RCT2_CALLFUNC_X(0x00685ADC, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - x = eax & 0xFFFF; - z = ebx & 0xFF; - y = ecx & 0xFFFF; - mapElement = (rct_map_element*)edx; - + get_map_coordinates_from_pos(x, y, 0xFFDE, &x, &y, &z, &mapElement); if (z == 0) return; @@ -730,7 +711,7 @@ static void window_footpath_place_path_at_point(int x, int y) // bp = 0x009DEA62 // dx = 0x009DEA60 // cx = 0x009DEA5E - sound_play_panned(SOUND_PLACE_ITEM, 0x8001); + sound_play_panned(SOUND_PLACE_ITEM, 0x8001, RCT2_GLOBAL(0x009DEA5E, uint16), RCT2_GLOBAL(0x009DEA60, uint16), RCT2_GLOBAL(0x009DEA62, uint16)); } } diff --git a/src/window_game_bottom_toolbar.c b/src/windows/game_bottom_toolbar.c similarity index 98% rename from src/window_game_bottom_toolbar.c rename to src/windows/game_bottom_toolbar.c index 46e983865e..0fc569aa68 100644 --- a/src/window_game_bottom_toolbar.c +++ b/src/windows/game_bottom_toolbar.c @@ -20,17 +20,17 @@ #include #include -#include "addresses.h" -#include "climate.h" -#include "date.h" -#include "news_item.h" -#include "park.h" -#include "peep.h" -#include "sprite.h" -#include "sprites.h" -#include "string_ids.h" -#include "widget.h" -#include "window.h" +#include "../addresses.h" +#include "../localisation/date.h" +#include "../localisation/localisation.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../management/news_item.h" +#include "../peep/peep.h" +#include "../sprites.h" +#include "../world/climate.h" +#include "../world/park.h" +#include "../world/sprite.h" enum WINDOW_GAME_BOTTOM_TOOLBAR_WIDGET_IDX { WIDX_LEFT_OUTSET, diff --git a/src/window_game_top_toolbar.c b/src/windows/game_top_toolbar.c similarity index 98% rename from src/window_game_top_toolbar.c rename to src/windows/game_top_toolbar.c index a81eaf85df..17d294f7a9 100644 --- a/src/window_game_top_toolbar.c +++ b/src/windows/game_top_toolbar.c @@ -19,14 +19,14 @@ *****************************************************************************/ #include -#include "addresses.h" -#include "game.h" -#include "sprites.h" -#include "string_ids.h" -#include "widget.h" -#include "window.h" -#include "window_dropdown.h" -#include "viewport.h" +#include "../addresses.h" +#include "../game.h" +#include "../sprites.h" +#include "../localisation/localisation.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "dropdown.h" +#include "../interface/viewport.h" enum { WIDX_PAUSE, @@ -260,7 +260,6 @@ static void window_game_top_toolbar_mouseup() if (!tool_set(w, WIDX_SCENERY, 0)) { RCT2_GLOBAL(0x009DE518, uint32) |= (1 << 6); window_scenery_open(); - //RCT2_CALLPROC_EBPSAFE(0x006E0FEF); } break; case WIDX_PATH: @@ -281,7 +280,7 @@ static void window_game_top_toolbar_mouseup() window_park_entrance_open(); break; case WIDX_STAFF: - window_staff_open(); + window_staff_list_open(); break; case WIDX_GUESTS: window_guest_list_open(); diff --git a/src/windows/guest.c b/src/windows/guest.c new file mode 100644 index 0000000000..e72a39a5d1 --- /dev/null +++ b/src/windows/guest.c @@ -0,0 +1,2208 @@ +/***************************************************************************** +* Copyright (c) 2014 Ted John, Duncan Frost +* OpenRCT2, an open source clone of Roller Coaster Tycoon 2. +* +* This file is part of OpenRCT2. +* +* OpenRCT2 is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. + +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. + +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*****************************************************************************/ + +#include "../addresses.h" +#include "../game.h" +#include "../world/map.h" +#include "../management/marketing.h" +#include "../peep/peep.h" +#include "../peep/staff.h" +#include "../ride/ride.h" +#include "../scenario.h" +#include "../localisation/localisation.h" +#include "../world/sprite.h" +#include "../sprites.h" +#include "../interface/viewport.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "dropdown.h" +#include "error.h" + +enum WINDOW_GUEST_PAGE { + WINDOW_GUEST_OVERVIEW, + WINDOW_GUEST_STATS, + WINDOW_GUEST_RIDES, + WINDOW_GUEST_FINANCE, + WINDOW_GUEST_THOUGHTS, + WINDOW_GUEST_INVENTORY +}; + +enum WINDOW_GUEST_WIDGET_IDX { + WIDX_BACKGROUND, + WIDX_TITLE, + WIDX_CLOSE, + WIDX_PAGE_BACKGROUND, + WIDX_TAB_1, + WIDX_TAB_2, + WIDX_TAB_3, + WIDX_TAB_4, + WIDX_TAB_5, + WIDX_TAB_6, + + WIDX_MARQUEE = 10, + WIDX_VIEWPORT, + WIDX_ACTION_LBL, + WIDX_PICKUP, + WIDX_RENAME, + WIDX_LOCATE, + WIDX_TRACK, + + WIDX_RIDE_SCROLL = 10 +}; + +void window_guest_emptysub(){}; + +rct_widget window_guest_overview_widgets[] = { + { WWT_FRAME, 0, 0, 191, 0, 156, 0x0FFFFFFFF, STR_NONE }, // Panel / Background + { WWT_CAPTION, 0, 1, 190, 1, 14, 865, STR_WINDOW_TITLE_TIP }, // Title + { WWT_CLOSEBOX, 0, 179, 189, 2, 13, 824, STR_CLOSE_WINDOW_TIP }, // Close x button + { WWT_RESIZE, 1, 1, 191, 43, 156, 0x0FFFFFFFF, STR_NONE }, // Resize + { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, 1938 }, // Tab 1 + { WWT_TAB, 1, 73, 64, 17, 43, 0x2000144E, 1940}, // Tab 2 + { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, 1941}, // Tab 3 + { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, 1942}, // Tab 4 + { WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, 1943}, // Tab 5 + { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, 1944}, // Tab 6 + { WWT_12, 1, 3, 166, 45, 56, 0x0FFFFFFFF, STR_NONE}, // Label Thought marquee + { WWT_VIEWPORT, 1, 3, 166, 57, 143, 0x0FFFFFFFF, STR_NONE }, // Viewport + { WWT_12, 1, 3, 166, 144, 154, 0x0FFFFFFFF, STR_NONE}, // Label Action + { WWT_FLATBTN, 1, 167, 190, 45, 68, 0x1436, 1706}, // Pickup Button + { WWT_FLATBTN, 1, 167, 190, 69, 92, SPR_RENAME, 1055}, // Rename Button + { WWT_FLATBTN, 1, 167, 190, 93, 116, SPR_LOCATE, STR_LOCATE_SUBJECT_TIP},// Locate Button + { WWT_FLATBTN, 1, 167, 190, 117, 140, SPR_TRACK_PEEP, 1930}, // Track Button + { WIDGETS_END }, +}; + +rct_widget window_guest_stats_widgets[] = { + {WWT_FRAME, 0, 0, 191, 0, 156, -1, STR_NONE}, + {WWT_CAPTION, 0, 1, 190, 1, 14, 865, STR_WINDOW_TITLE_TIP}, + {WWT_CLOSEBOX, 0, 179, 189, 2, 13, 824, STR_CLOSE_WINDOW_TIP}, + {WWT_RESIZE, 1, 0, 191, 43, 156, -1, STR_NONE}, + {WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, 1938}, + {WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, 1940}, + {WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, 1941}, + {WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, 1942}, + {WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, 1943}, + {WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, 1944}, + {WIDGETS_END}, +}; + +rct_widget window_guest_rides_widgets[] = { + {WWT_FRAME, 0, 0, 191, 0, 156, -1, STR_NONE}, + {WWT_CAPTION, 0, 1, 190, 1, 14, 865, STR_WINDOW_TITLE_TIP}, + {WWT_CLOSEBOX, 0, 179, 189, 2, 13, 824, STR_CLOSE_WINDOW_TIP}, + {WWT_RESIZE, 1, 0, 191, 43, 156, -1, STR_NONE}, + {WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, 1938}, + {WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, 1940}, + {WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, 1941}, + {WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, 1942}, + {WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, 1943}, + {WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, 1944}, + {WWT_SCROLL, 1, 3, 188, 57, 143, 2, STR_NONE}, + {WIDGETS_END}, +}; + +rct_widget window_guest_finance_widgets[] = { + {WWT_FRAME, 0, 0, 191, 0, 156, -1, STR_NONE}, + {WWT_CAPTION, 0, 1, 190, 1, 14, 865, STR_WINDOW_TITLE_TIP}, + {WWT_CLOSEBOX, 0, 179, 189, 2, 13, 824, STR_CLOSE_WINDOW_TIP}, + {WWT_RESIZE, 1, 0, 191, 43, 156, -1, STR_NONE}, + {WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, 1938}, + {WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, 1940}, + {WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, 1941}, + {WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, 1942}, + {WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, 1943}, + {WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, 1944}, + {WIDGETS_END}, +}; + +rct_widget window_guest_thoughts_widgets[] = { + {WWT_FRAME, 0, 0, 191, 0, 156, -1, STR_NONE}, + {WWT_CAPTION, 0, 1, 190, 1, 14, 865, STR_WINDOW_TITLE_TIP}, + {WWT_CLOSEBOX, 0, 179, 189, 2, 13, 824, STR_CLOSE_WINDOW_TIP}, + {WWT_RESIZE, 1, 0, 191, 43, 156, -1, STR_NONE}, + {WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, 1938}, + {WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, 1940}, + {WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, 1941}, + {WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, 1942}, + {WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, 1943}, + {WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, 1944}, + {WIDGETS_END}, +}; + +rct_widget window_guest_inventory_widgets[] = { + {WWT_FRAME, 0, 0, 191, 0, 156, -1, STR_NONE}, + {WWT_CAPTION, 0, 1, 190, 1, 14, 865, STR_WINDOW_TITLE_TIP}, + {WWT_CLOSEBOX, 0, 179, 189, 2, 13, 824, STR_CLOSE_WINDOW_TIP}, + {WWT_RESIZE, 1, 0, 191, 43, 156, -1, STR_NONE}, + {WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, 1938}, + {WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, 1940}, + {WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, 1941}, + {WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, 1942}, + {WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, 1943}, + {WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, 1944}, + {WIDGETS_END}, +}; + +//0x981D0C +rct_widget *window_guest_page_widgets[] = { + window_guest_overview_widgets, + window_guest_stats_widgets, + window_guest_rides_widgets, + window_guest_finance_widgets, + window_guest_thoughts_widgets, + window_guest_inventory_widgets +}; + +void window_guest_set_page(rct_window* w, int page); +void window_guest_disable_widgets(rct_window* w); +void window_guest_viewport_init(rct_window* w); + +void window_guest_overview_close(); +void window_guest_overview_resize(); +void window_guest_overview_mouse_up(); +void window_guest_overview_paint(); +void window_guest_overview_invalidate(); +void window_guest_overview_viewport_init_wrapper(); +void window_guest_overview_update(rct_window* w); +void window_guest_overview_text_input(); +void window_guest_overview_tool_update(); +void window_guest_overview_tool_down(); +void window_guest_overview_tool_abort(); + +static void* window_guest_overview_events[] = { + window_guest_overview_close, + window_guest_overview_mouse_up, + window_guest_overview_resize, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_overview_update, + window_guest_emptysub, + window_guest_emptysub, + window_guest_overview_tool_update,//tool_update + window_guest_overview_tool_down,//tool_down + window_guest_emptysub, + window_guest_emptysub, + window_guest_overview_tool_abort,//tool_abort + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_overview_text_input,//text_input + window_guest_overview_viewport_init_wrapper, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_overview_invalidate, //Invalidate + window_guest_overview_paint, //Paint + window_guest_emptysub +}; + +void window_guest_mouse_up(); +void window_guest_unknown_05(); + +void window_guest_stats_resize(); +void window_guest_stats_update(); +void window_guest_stats_invalidate(); +void window_guest_stats_paint(); + +static void* window_guest_stats_events[] = { + window_guest_emptysub, + window_guest_mouse_up, //mouse_up + window_guest_stats_resize, //resize + window_guest_emptysub, + window_guest_emptysub, + window_guest_unknown_05, + window_guest_stats_update, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_stats_invalidate, //invalidate + window_guest_stats_paint, //paint + window_guest_emptysub +}; + +void window_guest_rides_resize(); +void window_guest_rides_update(); +void window_guest_rides_tooltip(); +void window_guest_rides_scroll_get_size(); +void window_guest_rides_scroll_mouse_down(); +void window_guest_rides_scroll_mouse_over(); +void window_guest_rides_invalidate(); +void window_guest_rides_paint(); +void window_guest_rides_scroll_paint(); + +static void* window_guest_rides_events[] = { + window_guest_emptysub, + window_guest_mouse_up, //mouse_up + window_guest_rides_resize, //resize + window_guest_emptysub, + window_guest_emptysub, + window_guest_unknown_05, + window_guest_rides_update, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_rides_scroll_get_size, //scroll_get_size + window_guest_rides_scroll_mouse_down, //scroll_mouse_down + window_guest_emptysub, + window_guest_rides_scroll_mouse_over, //scroll_mouse_over + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_rides_tooltip, //tooltip + window_guest_emptysub, + window_guest_emptysub, + window_guest_rides_invalidate, //invalidate + window_guest_rides_paint, //paint + window_guest_rides_scroll_paint //scroll_paint +}; + +void window_guest_finance_resize(); +void window_guest_finance_update(); +void window_guest_finance_invalidate(); +void window_guest_finance_paint(); + +static void* window_guest_finance_events[] = { + window_guest_emptysub, + window_guest_mouse_up, //mouse_up + window_guest_finance_resize, //resize + window_guest_emptysub, + window_guest_emptysub, + window_guest_unknown_05, + window_guest_finance_update, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_finance_invalidate, //invalidate + window_guest_finance_paint, //paint + window_guest_emptysub +}; + +void window_guest_thoughts_resize(); +void window_guest_thoughts_update(); +void window_guest_thoughts_invalidate(); +void window_guest_thoughts_paint(); + +static void* window_guest_thoughts_events[] = { + window_guest_emptysub, + window_guest_mouse_up, //mouse_up + window_guest_thoughts_resize, //resize + window_guest_emptysub, + window_guest_emptysub, + window_guest_unknown_05, + window_guest_thoughts_update, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_thoughts_invalidate, //invalidate + window_guest_thoughts_paint, //paint + window_guest_emptysub +}; + +void window_guest_inventory_resize(); +void window_guest_inventory_update(); +void window_guest_inventory_invalidate(); +void window_guest_inventory_paint(); + +static void* window_guest_inventory_events[] = { + window_guest_emptysub, + window_guest_mouse_up, //mouse_up + window_guest_inventory_resize, //resize + window_guest_emptysub, + window_guest_emptysub, + window_guest_unknown_05, + window_guest_inventory_update, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_emptysub, + window_guest_inventory_invalidate, //invalidate + window_guest_inventory_paint, //paint + window_guest_emptysub +}; + +//0x981D24 +void* window_guest_page_events[] = { + window_guest_overview_events, + window_guest_stats_events, + window_guest_rides_events, + window_guest_finance_events, + window_guest_thoughts_events, + window_guest_inventory_events +}; + +//0x981D3C +uint32 window_guest_page_enabled_widgets[] = { + (1 << WIDX_CLOSE) | + (1 << WIDX_TAB_1) | + (1 << WIDX_TAB_2) | + (1 << WIDX_TAB_3) | + (1 << WIDX_TAB_4) | + (1 << WIDX_TAB_5) | + (1 << WIDX_TAB_6) | + (1 << WIDX_RENAME)| + (1 << WIDX_PICKUP)| + (1 << WIDX_LOCATE)| + (1 << WIDX_TRACK), + + (1 << WIDX_CLOSE) | + (1 << WIDX_TAB_1) | + (1 << WIDX_TAB_2) | + (1 << WIDX_TAB_3) | + (1 << WIDX_TAB_4) | + (1 << WIDX_TAB_5) | + (1 << WIDX_TAB_6), + + (1 << WIDX_CLOSE) | + (1 << WIDX_TAB_1) | + (1 << WIDX_TAB_2) | + (1 << WIDX_TAB_3) | + (1 << WIDX_TAB_4) | + (1 << WIDX_TAB_5) | + (1 << WIDX_TAB_6) | + (1 << WIDX_RIDE_SCROLL), + + (1 << WIDX_CLOSE) | + (1 << WIDX_TAB_1) | + (1 << WIDX_TAB_2) | + (1 << WIDX_TAB_3) | + (1 << WIDX_TAB_4) | + (1 << WIDX_TAB_5) | + (1 << WIDX_TAB_6), + + (1 << WIDX_CLOSE) | + (1 << WIDX_TAB_1) | + (1 << WIDX_TAB_2) | + (1 << WIDX_TAB_3) | + (1 << WIDX_TAB_4) | + (1 << WIDX_TAB_5) | + (1 << WIDX_TAB_6), + + (1 << WIDX_CLOSE) | + (1 << WIDX_TAB_1) | + (1 << WIDX_TAB_2) | + (1 << WIDX_TAB_3) | + (1 << WIDX_TAB_4) | + (1 << WIDX_TAB_5) | + (1 << WIDX_TAB_6) +}; + +/** + * rct2: 0x006989E9 + * + */ +void window_guest_open(rct_peep* peep){ + + if (peep->type == PEEP_TYPE_STAFF){ + window_staff_open(peep); + return; + } + + rct_window* window; + + window = window_bring_to_front_by_id(WC_PEEP, peep->sprite_index); + if (window == NULL){ + window = window_create_auto_pos(192, 157, (uint32*)window_guest_overview_events, WC_PEEP, 0); + window->widgets = window_guest_overview_widgets; + window->enabled_widgets = window_guest_page_enabled_widgets[0]; + window->number = peep->sprite_index; + window->page = 0; + window->viewport_focus_coordinates.y = 0; + window->frame_no = 0; + window->list_information_type = 0; + window->var_492 = 0; + window->var_494 = 0; + window_guest_disable_widgets(window); + window->min_width = 192; + window->min_height = 157; + window->max_width = 500; + window->max_height = 450; + window->flags = WF_RESIZABLE; + window->no_list_items = 0; + window->selected_list_item = -1; + window->colours[0] = 1; + window->colours[1] = 15; + window->colours[2] = 15; + window->viewport_focus_coordinates.y = -1; + } + + window->page = 0; + window_invalidate(window); + + window->widgets = window_guest_page_widgets[WINDOW_GUEST_OVERVIEW]; + window->enabled_widgets = window_guest_page_enabled_widgets[WINDOW_GUEST_OVERVIEW]; + window->var_020 = RCT2_GLOBAL(0x981D54,uint32); + window->event_handlers = window_guest_page_events[WINDOW_GUEST_OVERVIEW]; + window->pressed_widgets = 0; + + window_guest_disable_widgets(window); + window_init_scroll_widgets(window); + window_guest_viewport_init(window); +} + +/* rct2: 0x006987A6 + * Disables the finance tab when no money. + * Disables peep pickup when in certain no pickup states. + */ +void window_guest_disable_widgets(rct_window* w){ + rct_peep* peep = &g_sprite_list[w->number].peep; + uint64 disabled_widgets = 0; + + if (peep_can_be_picked_up(peep)){ + if (w->disabled_widgets & (1 << WIDX_PICKUP)) + window_invalidate(w); + } + else{ + disabled_widgets = (1 << WIDX_PICKUP); + if (!(w->disabled_widgets & (1 << WIDX_PICKUP))) + window_invalidate(w); + } + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY){ + disabled_widgets |= (1 << WIDX_TAB_4); //Disable finance tab if no money + } + w->disabled_widgets = disabled_widgets; +} + +/* rct2: 0x00696A75 */ +void window_guest_overview_close(){ + rct_window* w; + + window_get_register(w); + + if (RCT2_GLOBAL(0x9DE518,uint32) & (1<<3)){ + if (w->classification == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS,rct_windowclass) && + w->number == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER,rct_windownumber)) + tool_cancel(); + } +} + +/* rct2: 0x00696FBE */ +void window_guest_overview_resize(){ + rct_window* w; + + window_get_register(w); + + window_guest_disable_widgets(w); + RCT2_CALLPROC_EBPSAFE(w->event_handlers[WE_INVALIDATE]); + + widget_invalidate(WC_PEEP, w->number, WIDX_MARQUEE); + + window_set_resize(w, 192, 159, 500, 450); + + rct_viewport* view = w->viewport; + + if (view){ + if ((w->width - 30) == view->width){ + if ((w->height - 72) == view->height){ + window_guest_viewport_init(w); + return; + } + } + uint8 zoom_amount = 1 << view->zoom; + view->width = w->width - 30; + view->height = w->height - 72; + view->view_width = view->width / zoom_amount; + view->view_height = view->height / zoom_amount; + } + window_guest_viewport_init(w); +} + +/* rct2: 0x00696A06 */ +void window_guest_overview_mouse_up(){ + short widgetIndex; + rct_window* w; + window_widget_get_registers(w, widgetIndex); + rct_peep* peep = GET_PEEP(w->number); + + switch(widgetIndex){ + case WIDX_CLOSE: + window_close(w); + break; + case WIDX_TAB_1: + case WIDX_TAB_2: + case WIDX_TAB_3: + case WIDX_TAB_4: + case WIDX_TAB_5: + case WIDX_TAB_6: + window_guest_set_page(w, widgetIndex - WIDX_TAB_1); + break; + case WIDX_PICKUP: + if (!peep_can_be_picked_up(peep)) { + return; + } + if (tool_set(w, widgetIndex, 7)) { + return; + } + + w->var_48C = peep->x; + + RCT2_CALLPROC_X(0x0069A512, 0, 0, 0, 0, (int)peep, 0, 0); + RCT2_CALLPROC_X(0x006EC473, 0, 0, 0, 0, (int)peep, 0, 0); + + RCT2_CALLPROC_X(0x0069E9D3, 0x8000, 0, peep->y, peep->z, (int)peep, 0, 0); + RCT2_CALLPROC_X(0x0069A409, 0, 0, 0, 0, (int)peep, 0, 0); + peep->state = 9; + peep->pad_2C = 0; + RCT2_CALLPROC_X(0x0069A42F, 0, 0, 0, 0, (int)peep, 0, 0); + break; + case WIDX_RENAME: + window_show_textinput(w, (int)widgetIndex, 0x5AC, 0x5AD, peep->name_string_idx); + break; + case WIDX_LOCATE: + window_scroll_to_viewport(w); + break; + case WIDX_TRACK: + g_sprite_list[w->number].peep.flags ^= PEEP_FLAGS_TRACKING; + break; + } +} + +/* rct2: 0x696AA0 */ +void window_guest_set_page(rct_window* w, int page){ + if (RCT2_GLOBAL(0x9DE518,uint32) & (1 << 3)) + { + if(w->number == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber) && + w->classification == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass)) + tool_cancel(); + + } + int listen = 0; + if ( page == WINDOW_GUEST_OVERVIEW && w->page==WINDOW_GUEST_OVERVIEW && w->viewport){ + if(!(w->viewport->flags & VIEWPORT_FLAG_SOUND_ON)) + listen = 1; + } + + + w->page = page; + w->frame_no = 0; + w->no_list_items = 0; + w->selected_list_item = -1; + + rct_viewport* viewport = w->viewport; + w->viewport = 0; + if (viewport){ + viewport->width = 0; + } + + w->enabled_widgets = window_guest_page_enabled_widgets[page]; + w->var_020 = RCT2_ADDRESS(0x981D54,uint32)[page]; + w->event_handlers = window_guest_page_events[page]; + w->pressed_widgets = 0; + w->widgets = window_guest_page_widgets[page]; + window_guest_disable_widgets(w); + window_invalidate(w); + + RCT2_CALLPROC_X(w->event_handlers[WE_RESIZE], 0, 0, 0, 0, (int)w, 0, 0); + RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + + window_init_scroll_widgets(w); + window_invalidate(w); + + if (listen && w->viewport) w->viewport->flags |= VIEWPORT_FLAG_SOUND_ON; +} + +void window_guest_overview_viewport_init_wrapper(){ + rct_window* w; + window_get_register(w); + + window_guest_viewport_init(w); +} + +/* rct2: 0x0069883C */ +void window_guest_viewport_init(rct_window* w){ + if (w->page != WINDOW_GUEST_OVERVIEW) return; + + union{ + sprite_focus sprite; + coordinate_focus coordinate; + } focus; //The focus will be either a sprite or a coordinate. + + focus.sprite.sprite_id = w->number; + + rct_peep* peep = GET_PEEP(w->number); + + if (peep->state == PEEP_STATE_PICKED){ + focus.sprite.sprite_id = -1; + } + else{ + uint8 final_check = 1; + if (peep->state == PEEP_STATE_ON_RIDE + || peep->state == PEEP_STATE_ENTERING_RIDE + || (peep->state == PEEP_STATE_LEAVING_RIDE && peep->x == SPRITE_LOCATION_NULL)){ + + rct_ride* ride = &(RCT2_ADDRESS(RCT2_ADDRESS_RIDE_LIST, rct_ride)[peep->current_ride]); + if (ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK){ + rct_vehicle* train = GET_VEHICLE(ride->vehicles[peep->current_train]); + int car = peep->current_car; + + for (; car != 0; car--){ + train = GET_VEHICLE(train->next_vehicle_on_train); + } + + focus.sprite.sprite_id = train->sprite_index; + final_check = 0; + } + } + if (peep->x == SPRITE_LOCATION_NULL && final_check){ + rct_ride* ride = &(RCT2_ADDRESS(RCT2_ADDRESS_RIDE_LIST, rct_ride)[peep->current_ride]); + int x = ride->overall_view & 0xFF * 32 + 16; + int y = (ride->overall_view >> 8) * 32 + 16; + int height = map_element_height(x, y); + height += 32; + focus.coordinate.x = x; + focus.coordinate.y = y; + focus.coordinate.z = height; + focus.sprite.type |= VIEWPORT_FOCUS_TYPE_COORDINATE; + } + else{ + focus.sprite.type |= VIEWPORT_FOCUS_TYPE_SPRITE | VIEWPORT_FOCUS_TYPE_COORDINATE; + focus.sprite.pad_486 &= 0xFFFF; + } + focus.coordinate.rotation = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8); + } + + uint16 viewport_flags; + + if (w->viewport){ + //Check all combos, for now skipping y and rot + if (focus.coordinate.x == w->viewport_focus_coordinates.x && + focus.coordinate.y == w->viewport_focus_coordinates.y && + focus.coordinate.z == w->viewport_focus_coordinates.z && + focus.coordinate.rotation == w->viewport_focus_coordinates.rotation) + return; + + viewport_flags = w->viewport->flags; + w->viewport->width = 0; + w->viewport = 0; + + viewport_update_pointers(); + } + else{ + viewport_flags = 0; + if (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) & 0x1) + viewport_flags |= VIEWPORT_FLAG_GRIDLINES; + } + + RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + + w->viewport_focus_coordinates.x = focus.coordinate.x; + w->viewport_focus_coordinates.y = focus.coordinate.y; + w->viewport_focus_coordinates.z = focus.coordinate.z; + w->viewport_focus_coordinates.rotation = focus.coordinate.rotation; + + if (peep->state != PEEP_STATE_PICKED){ + if (!(w->viewport)){ + rct_widget* view_widget = &w->widgets[WIDX_VIEWPORT]; + + int x = view_widget->left + 1 + w->x; + int y = view_widget->top + 1 + w->y; + int width = view_widget->right - view_widget->left - 1; + int height = view_widget->bottom - view_widget->top - 1; + + viewport_create(w, x, y, width, height, 0, focus.coordinate.x, focus.coordinate.y, focus.coordinate.z, focus.sprite.type & VIEWPORT_FOCUS_TYPE_MASK, focus.sprite.sprite_id); + w->flags |= WF_2; + window_invalidate(w); + } + } + + if (w->viewport) + w->viewport->flags = viewport_flags; + window_invalidate(w); +} + +/** + * rct2: 0x6983dd + * used by window_staff as well + */ +void window_guest_overview_tab_paint(rct_window* w, rct_drawpixelinfo* dpi){ + if (w->disabled_widgets & (1<widgets[WIDX_TAB_1]; + int width = widget->right - widget->left - 1; + int height = widget->bottom - widget->top - 1; + int x = widget->left + 1 + w->x; + int y = widget->top + 1 + w->y; + if (w->page == WINDOW_GUEST_OVERVIEW) height++; + + rct_drawpixelinfo* clip_dpi = clip_drawpixelinfo(dpi, x, width, y, height ); + if (!clip_dpi) return; + + x = 14; + y = 20; + + rct_peep* peep = GET_PEEP(w->number); + + if (peep->type == PEEP_TYPE_STAFF && peep->staff_type == STAFF_TYPE_ENTERTAINER) + y++; + + int ebx = *(RCT2_ADDRESS(0x982708, uint32*)[peep->sprite_type * 2]) + 1; + + int eax = 0; + + if (w->page == WINDOW_GUEST_OVERVIEW){ + eax = w->var_494>>16; + eax &= 0xFFFC; + } + ebx += eax; + + int sprite_id = ebx | (peep->tshirt_colour << 19) | (peep->trousers_colour << 24) | 0xA0000000; + gfx_draw_sprite( clip_dpi, sprite_id, x, y, 0); + + // If holding a balloon + if (ebx >= 0x2A1D && ebx < 0x2A3D){ + ebx += 32; + ebx |= (peep->balloon_colour << 19) | 0x20000000; + gfx_draw_sprite( clip_dpi, ebx, x, y, 0); + } + + // If holding umbrella + if (ebx >= 0x2BBD && ebx < 0x2BDD){ + ebx += 32; + ebx |= (peep->umbrella_colour << 19) | 0x20000000; + gfx_draw_sprite(clip_dpi, ebx, x, y, 0); + } + + // If wearing hat + if (ebx >= 0x29DD && ebx < 0x29FD){ + ebx += 32; + ebx |= (peep->hat_colour << 19) | 0x20000000; + gfx_draw_sprite( clip_dpi, ebx, x, y, 0); + } +} + +/* rct2: 0x69869b */ +void window_guest_stats_tab_paint(rct_window* w, rct_drawpixelinfo* dpi){ + if (w->disabled_widgets & (1 << WIDX_TAB_2)) + return; + + rct_widget* widget = &w->widgets[WIDX_TAB_2]; + int x = widget->left + w->x; + int y = widget->top + w->y; + + rct_peep* peep = GET_PEEP(w->number); + int image_id = get_peep_face_sprite_large(peep); + if (w->page == WINDOW_GUEST_STATS){ + // If currently viewing this tab animate tab + // if it is very sick or angry. + switch (image_id){ + case SPR_PEEP_LARGE_FACE_VERY_VERY_SICK: + image_id += (w->frame_no / 4) & 0xF; + break; + case SPR_PEEP_LARGE_FACE_VERY_SICK: + image_id += (w->frame_no / 8) & 0x3; + break; + case SPR_PEEP_LARGE_FACE_ANGRY: + image_id += (w->frame_no / 8) & 0x3; + break; + } + } + gfx_draw_sprite(dpi, image_id, x, y, 0); +} + +/* rct2: 0x69861F */ +void window_guest_rides_tab_paint(rct_window* w, rct_drawpixelinfo* dpi){ + if (w->disabled_widgets & (1 << WIDX_TAB_3)) return; + + rct_widget* widget = &w->widgets[WIDX_TAB_3]; + int x = widget->left + w->x; + int y = widget->top + w->y; + + int image_id = SPR_TAB_RIDE_0; + + if ( w->page == WINDOW_GUEST_RIDES ){ + image_id += (w->frame_no / 4) & 0xF; + } + + gfx_draw_sprite(dpi, image_id, x, y, 0); +} + +/* rct2: 0x698597 */ +void window_guest_finance_tab_paint(rct_window* w, rct_drawpixelinfo* dpi){ + if (w->disabled_widgets & (1 << WIDX_TAB_4)) return; + + rct_widget* widget = &w->widgets[WIDX_TAB_4]; + int x = widget->left + w->x; + int y = widget->top + w->y; + + int image_id = SPR_TAB_FINANCES_SUMMARY_0; + + if ( w->page == WINDOW_GUEST_FINANCE ){ + image_id += (w->frame_no / 2) & 0x7; + } + + gfx_draw_sprite(dpi, image_id, x, y, 0); +} + +/* rct2: 0x6985D8 */ +void window_guest_thoughts_tab_paint(rct_window* w, rct_drawpixelinfo* dpi){ + if (w->disabled_widgets & (1 << WIDX_TAB_5)) return; + + rct_widget* widget = &w->widgets[WIDX_TAB_5]; + int x = widget->left + w->x; + int y = widget->top + w->y; + + int image_id = 5269; + + if ( w->page == WINDOW_GUEST_THOUGHTS ){ + image_id += (w->frame_no / 2) & 0x7; + } + + gfx_draw_sprite(dpi, image_id, x, y, 0); +} + +/* rct2: 0x698661 */ +void window_guest_inventory_tab_paint(rct_window* w, rct_drawpixelinfo* dpi){ + if (w->disabled_widgets & (1 << WIDX_TAB_6)) return; + + rct_widget* widget = &w->widgets[WIDX_TAB_6]; + int x = widget->left + w->x; + int y = widget->top + w->y; + + int image_id = 5326; + + gfx_draw_sprite(dpi, image_id, x, y, 0); +} + +/* rct2: 0x696887 */ +void window_guest_overview_paint(){ + rct_window *w; + rct_drawpixelinfo *dpi; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + window_guest_overview_tab_paint(w, dpi); + window_guest_stats_tab_paint(w, dpi); + window_guest_rides_tab_paint(w, dpi); + window_guest_finance_tab_paint(w, dpi); + window_guest_thoughts_tab_paint(w, dpi); + window_guest_inventory_tab_paint(w, dpi); + + // Draw the viewport no sound sprite + if (w->viewport){ + window_draw_viewport(dpi, w); + rct_viewport* viewport = w->viewport; + if (viewport->flags & VIEWPORT_FLAG_SOUND_ON){ + gfx_draw_sprite(dpi, SPR_HEARING_VIEWPORT, w->x + 2, w->y + 2, 0); + } + } + + // Draw the centered label + uint32 argument1, argument2; + rct_peep* peep = GET_PEEP(w->number); + get_arguments_from_action(peep, &argument1, &argument2); + RCT2_GLOBAL(0x13CE952, uint32) = argument1; + RCT2_GLOBAL(0x13CE952 + 4, uint32) = argument2; + rct_widget* widget = &w->widgets[WIDX_ACTION_LBL]; + int x = (widget->left + widget->right) / 2 + w->x; + int y = w->y + widget->top - 1; + int width = widget->right - widget->left; + gfx_draw_string_centred_clipped(dpi, 1191, (void*)0x13CE952, 0, x, y, width); + + // Draw the marquee thought + widget = &w->widgets[WIDX_MARQUEE]; + width = widget->right - widget->left - 3; + int left = widget->left + 2 + w->x; + int top = widget->top + w->y; + int height = widget->bottom - widget->top; + rct_drawpixelinfo* dpi_marquee = clip_drawpixelinfo(dpi, left, width, top, height); + + if (!dpi_marquee)return; + int i = 0; + for (; i < PEEP_MAX_THOUGHTS; ++i){ + if (peep->thoughts[i].type == PEEP_THOUGHT_TYPE_NONE){ + w->list_information_type = 0; + return; + } + if (peep->thoughts[i].var_2 == 1){ // If a fresh thought + break; + } + } + if (i == PEEP_MAX_THOUGHTS){ + w->list_information_type = 0; + return; + } + + get_arguments_from_thought(peep->thoughts[i], &argument1, &argument2); + + RCT2_GLOBAL(0x13CE952, uint32) = argument1; + RCT2_GLOBAL(0x13CE952 + 4, uint32) = argument2; + RCT2_GLOBAL(0x13CE952 + 8, uint16) = 0; + + x = widget->right - widget->left - w->list_information_type; + gfx_draw_string_left(dpi_marquee, 1193, (void*)0x13CE952, 0, x, 0); +} + +/* rct2: 0x696749*/ +void window_guest_overview_invalidate(){ + rct_window* w; + window_get_register(w); + + if (window_guest_page_widgets[w->page] != w->widgets){ + w->widgets = window_guest_page_widgets[w->page]; + window_init_scroll_widgets(w); + } + + w->pressed_widgets &= ~(WIDX_TAB_1 | WIDX_TAB_2 |WIDX_TAB_3 |WIDX_TAB_4 |WIDX_TAB_5 |WIDX_TAB_6); + w->pressed_widgets |= 1ULL << (w->page + WIDX_TAB_1); + + rct_peep* peep = GET_PEEP(w->number); + RCT2_GLOBAL(0x13CE952,uint16) = peep->name_string_idx; + RCT2_GLOBAL(0x13CE954,uint32) = peep->id; + + w->pressed_widgets &= ~(1<flags & 0x8){ + w->pressed_widgets |= (1<width - 1; + window_guest_overview_widgets[WIDX_BACKGROUND].bottom = w->height - 1; + + window_guest_overview_widgets[WIDX_PAGE_BACKGROUND].right =w->width - 1; + window_guest_overview_widgets[WIDX_PAGE_BACKGROUND].bottom = w->height - 1; + + window_guest_overview_widgets[WIDX_TITLE].right = w->width - 2; + + window_guest_overview_widgets[WIDX_CLOSE].left = w->width - 13; + window_guest_overview_widgets[WIDX_CLOSE].right = w->width - 3; + + window_guest_overview_widgets[WIDX_VIEWPORT].right = w->width - 26; + window_guest_overview_widgets[WIDX_VIEWPORT].bottom = w->height - 14; + + window_guest_overview_widgets[WIDX_ACTION_LBL].top = w->height - 12; + window_guest_overview_widgets[WIDX_ACTION_LBL].bottom = w->height - 3; + window_guest_overview_widgets[WIDX_ACTION_LBL].right = w->width - 24; + + window_guest_overview_widgets[WIDX_MARQUEE].right = w->width - 24; + + window_guest_overview_widgets[WIDX_PICKUP].right = w->width - 2; + window_guest_overview_widgets[WIDX_RENAME].right = w->width - 2; + window_guest_overview_widgets[WIDX_LOCATE].right = w->width - 2; + window_guest_overview_widgets[WIDX_TRACK].right = w->width - 2; + + window_guest_overview_widgets[WIDX_PICKUP].left = w->width - 25; + window_guest_overview_widgets[WIDX_RENAME].left = w->width - 25; + window_guest_overview_widgets[WIDX_LOCATE].left = w->width - 25; + window_guest_overview_widgets[WIDX_TRACK].left = w->width - 25; + + window_align_tabs(w, WIDX_TAB_1, WIDX_TAB_6); +} + +/* rct2: 0x696F45 */ +void window_guest_overview_update(rct_window* w){ + int var_496 = w->var_494 >> 16; + var_496++; + var_496 %= 24; + w->var_494 &= 0x0000FFFF; + w->var_494 |= var_496 << 16; + + widget_invalidate(WC_PEEP, w->number, WIDX_TAB_1); + widget_invalidate(WC_PEEP, w->number, WIDX_TAB_2); + + w->list_information_type += 2; + + if ((w->var_494 & 0xFFFF) == 0xFFFF) + w->var_494 &= 0xFFFF0000; + else + w->var_494++; + + // Create the "I have the strangest feeling I am being watched thought" + if ((w->var_494 & 0xFFFF) >= 3840){ + if (!(w->var_494 & 0x3FF)){ + int rand = scenario_rand() & 0xFFFF; + if (rand <= 0x2AAA){ + rct_peep* peep = GET_PEEP(w->number); + RCT2_CALLPROC_X(0x699F5A, 0xFF47, 0, 0, 0, (int)peep, 0, 0); + } + } + } + +} + +/* rct2:0x696A6A */ +void window_guest_overview_text_input(){ + short widgetIndex; + rct_window *w; + char _cl; + uint32* text; + + window_text_input_get_registers(w, widgetIndex, _cl, text); + + if (widgetIndex != WIDX_RENAME)return; + + if (!_cl) return; + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, uint16) = 0x5AE; + + game_do_command(1, 1, w->number, *text, 22, *(text + 2), *(text + 1)); + game_do_command(2, 1, 0, *(text + 3), 22, *(text + 5), *(text + 4)); + game_do_command(0, 1, 0, *(text + 6), 22, *(text + 8), *(text + 7)); +} + +/* rct2: 0x696A5F */ +void window_guest_overview_tool_update(){ + short widgetIndex; + rct_window* w; + short x, y; + + window_tool_get_registers(w, widgetIndex, x, y); + + if (widgetIndex != WIDX_PICKUP) return; + + RCT2_CALLPROC_X(0x0068AAE1, x, y, 0, 0, (int)w, 0, 0); + + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 << 0); + int temp_y = y + 16; + + int eax = x, ecx = 0, edx = widgetIndex, edi = 0, esi = (int)w, ebp = 0; + RCT2_CALLFUNC_X(0x689726, &eax, &temp_y, &ecx, &edx, &esi, &edi, &ebp); + if (eax != 0x8000){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= 1; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16) = 4; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, uint16) = eax; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, uint16) = eax; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, uint16) = temp_y; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, uint16) = temp_y; + RCT2_CALLPROC_X(0x0068AAE1, eax, temp_y, 0, 0, (int)w, 0, 0); + } + + RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_SPRITE, sint32) = -1; + + int ebx; + get_map_coordinates_from_pos(x, y, 0, NULL, NULL, &ebx, NULL); + if (ebx == 0) + return; + + x--; + y += 16; + RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_X, uint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_Y, uint16) = y; + w->var_492++; + if (w->var_492 >= 48)w->var_492 = 0; + + rct_peep* peep; + peep = GET_PEEP(w->number); + ebx = (RCT2_ADDRESS(0x982708, uint32*)[peep->sprite_type * 2])[22]; + ebx += w->var_492 >> 2; + + ebp = peep->tshirt_colour << 19; + ecx = peep->trousers_colour << 24; + + ebx |= ebp | ecx | 0xA0000000; + RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_SPRITE, uint32) = ebx; +} + +/* rct2: 0x664F72 */ +int sub_664F72(int x, int y, int z){ + if (x > 0x1FFF || y > 0x1FFF){ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = 0x6C1; + return 1; + } + + rct_map_element* map_element = map_get_surface_element_at(x / 32, y / 32); + if (map_element->properties.surface.ownership & 0x20) return 0; + if (!(map_element->properties.surface.ownership & 0x10)){ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = 0x6C1; + return 1; + } + + z >>= 3; + if ((z & 0xFF) < map_element->base_height)return 0; + z = (z & 0xFF) - 2; + if (z > map_element->base_height)return 0; + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = 0x6C1; + return 1; +} + +/* rct2: 0x696A54 */ +void window_guest_overview_tool_down(){ + short widgetIndex; + rct_window* w; + short x, y; + + window_tool_get_registers(w, widgetIndex, x, y); + + if (widgetIndex != WIDX_PICKUP) return; + + int dest_x = x, dest_y = y, ecx = 0, edx = widgetIndex, edi = 0, esi = (int)w, ebp = 0; + dest_y += 16; + RCT2_CALLFUNC_X(0x689726, &dest_x, &dest_y, &ecx, &edx, &esi, &edi, &ebp); + + if (dest_x == 0x8000)return; + + // Set the coordinate of destination to be exactly + // in the middle of a tile. + dest_x += 16; + dest_y += 16; + // Set the tile coordinate to top left of tile + int tile_y = dest_y & 0xFFE0; + int tile_x = dest_x & 0xFFE0; + + int dest_z = ((uint8*)edx)[2] * 8 + 16; + + if (sub_664F72(tile_x, tile_y, dest_z)){ + window_error_open(0x785,-1); + return; + } + + int _edx = dest_z >> 3; + _edx &= 0xFFFF00FF; + _edx |= dest_z << 8; + _edx += 0x100; + int flags = RCT2_CALLPROC_X(0x68B93A, tile_x, 0xF, tile_y, _edx, (int)w, 0, 0); + + if (flags & 0x100){ + if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) != 0x3A5 ){ + if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) != 0x49B){ + window_error_open(0x785, -1); + return; + } + } + } + + rct_peep* peep = GET_PEEP(w->number); + RCT2_CALLPROC_X(0x0069E9D3, dest_x, 0, dest_y, dest_z, (int)peep, 0, 0); + RCT2_CALLPROC_X(0x006EC473, 0, 0, 0, 0, (int)peep, 0, 0); + RCT2_CALLPROC_X(0x0069A409, 0, 0, 0, 0, (int)peep, 0, 0); + peep->state = 0; + RCT2_CALLPROC_X(0x0069A42F, 0, 0, 0, 0, (int)peep, 0, 0); + peep->var_71 = 0xFF; + peep->var_6D = 0; + peep->var_70 = 0; + peep->var_6E = 0xFF; + peep->var_C4 = 0; + + peep->happiness_growth_rate -= 10; + if (peep->happiness_growth_rate < 0)peep->happiness_growth_rate = 0; + + RCT2_CALLPROC_X(0x00693B58, 0, 0, 0, 0, (int)peep, 0, 0); + tool_cancel(); + RCT2_GLOBAL(0x9DE550, sint32) = -1; +} + +/* rct2: 0x696A49 */ +void window_guest_overview_tool_abort(){ + short widgetIndex; + rct_window* w; + short x, y; + + window_tool_get_registers(w, widgetIndex, x, y); + if (widgetIndex != WIDX_PICKUP) return; + + rct_peep* peep = GET_PEEP(w->number); + if (peep->state != PEEP_STATE_PICKED) return; + + RCT2_CALLPROC_X(0x0069E9D3, w->var_48C, 0, peep->y, peep->z + 8, (int)peep, 0, 0); + RCT2_CALLPROC_X(0x006EC473, 0, 0, 0, 0, (int)peep, 0, 0); + + if (peep->x != 0x8000){ + RCT2_CALLPROC_X(0x0069A409, 0, 0, 0, 0, (int)peep, 0, 0); + peep->state = 0; + RCT2_CALLPROC_X(0x0069A42F, 0, 0, 0, 0, (int)peep, 0, 0); + peep->var_71 = 0xFF; + peep->var_6D = 0; + peep->var_70 = 0; + peep->var_6E = 0; + peep->var_C4 = 0; + } + + RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_SPRITE, sint32) = -1; +} + +/* rct2:0x69744F, 0x697795, 0x697BDD, 0x697E18, 0x698279 + * This is a combination of 5 functions that were identical + */ +void window_guest_mouse_up(){ + short widgetIndex; + rct_window* w; + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex){ + case WIDX_CLOSE: + window_close(w); + break; + case WIDX_TAB_1: + case WIDX_TAB_2: + case WIDX_TAB_3: + case WIDX_TAB_4: + case WIDX_TAB_5: + case WIDX_TAB_6: + window_guest_set_page(w, widgetIndex - WIDX_TAB_1); + break; + } +} + +/* rct2: 0x697488 */ +void window_guest_stats_resize(){ + rct_window* w; + window_get_register(w); + + window_set_resize(w, 192, 162, 192, 162); +} + +/* rct2: 0x6974ED, 0x00697959, 0x00697C7B, 0x00697ED2, 0x00698333 + * This is a combination of 5 functions that were identical + */ +void window_guest_unknown_05(){ + rct_window* w; + window_get_register(w); + + widget_invalidate(WC_PEEP, w->number, WIDX_TAB_1); +} + +/* rct2: 0x69746A */ +void window_guest_stats_update(){ + rct_window* w; + window_get_register(w); + + w->frame_no++; + rct_peep* peep = GET_PEEP(w->number); + peep->var_45 &= ~(1<<1); + + window_invalidate(w); +} + +/* rct2: 0x69707D */ +void window_guest_stats_invalidate(){ + rct_window* w; + window_get_register(w); + + if (w->widgets != window_guest_page_widgets[w->page]) { + w->widgets = window_guest_page_widgets[w->page]; + window_init_scroll_widgets(w); + } + + w->pressed_widgets |= 1ULL << (w->page + WIDX_TAB_1); + + rct_peep* peep = GET_PEEP(w->number); + RCT2_GLOBAL(0x13CE952, uint16) = peep->name_string_idx; + RCT2_GLOBAL(0x13CE954, uint32) = peep->id; + + window_guest_stats_widgets[WIDX_BACKGROUND].right = w->width - 1; + window_guest_stats_widgets[WIDX_BACKGROUND].bottom = w->height - 1; + + window_guest_stats_widgets[WIDX_PAGE_BACKGROUND].right = w->width - 1; + window_guest_stats_widgets[WIDX_PAGE_BACKGROUND].bottom = w->height - 1; + + window_guest_stats_widgets[WIDX_TITLE].right = w->width - 2; + + window_guest_stats_widgets[WIDX_CLOSE].left = w->width - 13; + window_guest_stats_widgets[WIDX_CLOSE].right = w->width - 3; + + window_align_tabs(w, WIDX_TAB_1, WIDX_TAB_6); +} + +/** +* +* rct2: 0x0066ECC1 +* +* ebp: colour, contains flag 0x80000000 for blinking +*/ +void window_guest_stats_bars_paint(int value, int x, int y, rct_window *w, rct_drawpixelinfo *dpi, int colour){ + //RCT2_CALLPROC_X(0x6974FC, value, 0, x, y, (int)w, (int)dpi, colour); + + value *= 0x76; + value >>= 8; + + gfx_fill_rect_inset(dpi, x + 0x3A, y + 1, x + 0x3A + 0x79, y + 9, w->colours[1], 0x30); + + int blink_flag = colour & (1 << 0x1F); //0x80000000 + colour &= ~(1 << 0x1F); + if (!blink_flag || + RCT2_GLOBAL(0x009DEA6E, uint8) != 0 || + (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) & 8) == 0) + { + if (value <= 2) + return; + gfx_fill_rect_inset(dpi, x + 0x3C, y + 2, x + 0x3C + value - 1, y + 8, colour, 0); + } + +} + +/* rct2: 0x0069711D */ +void window_guest_stats_paint(){ + rct_window *w; + rct_drawpixelinfo *dpi; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + window_guest_overview_tab_paint(w, dpi); + window_guest_stats_tab_paint(w, dpi); + window_guest_rides_tab_paint(w, dpi); + window_guest_finance_tab_paint(w, dpi); + window_guest_thoughts_tab_paint(w, dpi); + window_guest_inventory_tab_paint(w, dpi); + + //ebx + rct_peep* peep = GET_PEEP(w->number); + + // Not sure why this is not stats widgets + //cx + int x = w->x + window_guest_rides_widgets[WIDX_PAGE_BACKGROUND].left + 4; + //dx + int y = w->y + window_guest_rides_widgets[WIDX_PAGE_BACKGROUND].top + 4; + + //Happiness + gfx_draw_string_left(dpi, 1662, (void*)0x13CE952, 0, x, y); + + int happiness = peep->happiness; + if (happiness < 10)happiness = 10; + int ebp = 14; + if (happiness < 50){ + ebp |= 0x80000000; + } + window_guest_stats_bars_paint(happiness, x, y, w, dpi, ebp); + + //Energy + y += 10; + gfx_draw_string_left(dpi, 1664, (void*)0x13CE952, 0, x, y); + + int energy = ((peep->energy - 32) * 85) / 32; + ebp = 14; + if (energy < 50){ + ebp |= 0x80000000; + } + if (energy < 10)energy = 10; + window_guest_stats_bars_paint(energy, x, y, w, dpi, ebp); + + //Hunger + y += 10; + gfx_draw_string_left(dpi, 1665, (void*)0x13CE952, 0, x, y); + + int hunger = peep->hunger; + if (hunger > 190) hunger = 190; + + hunger -= 32; + if (hunger < 0) hunger = 0; + hunger *= 51; + hunger /= 32; + hunger = 0xFF & ~hunger; + + ebp = 28; + if (hunger > 170){ + ebp |= 0x80000000; + } + window_guest_stats_bars_paint(hunger, x, y, w, dpi, ebp); + + //Thirst + y += 10; + gfx_draw_string_left(dpi, 1666, (void*)0x13CE952, 0, x, y); + + int thirst = peep->thirst; + if (thirst > 190) thirst = 190; + + thirst -= 32; + if (thirst < 0) thirst = 0; + thirst *= 51; + thirst /= 32; + thirst = 0xFF & ~thirst; + + ebp = 28; + if (thirst > 170){ + ebp |= 0x80000000; + } + window_guest_stats_bars_paint(thirst, x, y, w, dpi, ebp); + + //Nausea + y += 10; + gfx_draw_string_left(dpi, 1663, (void*)0x13CE952, 0, x, y); + + int nausea = peep->nausea - 32; + + if (nausea < 0) nausea = 0; + nausea *= 36; + nausea /= 32; + + ebp = 28; + if (nausea > 120){ + ebp |= 0x80000000; + } + window_guest_stats_bars_paint(nausea, x, y, w, dpi, ebp); + + //Bathroom + y += 10; + gfx_draw_string_left(dpi, 1667, (void*)0x13CE952, 0, x, y); + + int bathroom = peep->bathroom - 32; + if (bathroom > 210) bathroom = 210; + + bathroom -= 32; + if (bathroom < 0) bathroom = 0; + bathroom *= 45; + bathroom /= 32; + + ebp = 28; + if (bathroom > 160){ + ebp |= 0x80000000; + } + window_guest_stats_bars_paint(bathroom, x, y, w, dpi, ebp); + + // Time in park + y += 11; + if (peep->time_in_park != -1){ + int eax = RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, uint32); + eax -= peep->time_in_park; + eax >>= 11; + RCT2_GLOBAL(0x13CE952, uint16) = eax & 0xFFFF; + gfx_draw_string_left(dpi, 1458, (void*)0x13CE952, 0, x, y); + } + + y += 19; + gfx_fill_rect_inset(dpi, x, y - 6, x + 179, y - 5, w->colours[1], 32); + + // Preferred Ride + gfx_draw_string_left(dpi, 1657, (void*)0, 0, x, y); + y += 10; + + // Intensity + int intensity = peep->intensity / 16; + RCT2_GLOBAL(0x13CE952, uint16) = intensity; + int string_id = 1658; + if (peep->intensity & 0xF){ + RCT2_GLOBAL(0x13CE952, uint16) = peep->intensity & 0xF; + RCT2_GLOBAL(0x13CE954, uint16) = intensity; + string_id = 1659; + if (intensity == 15) string_id = 1660; + } + + gfx_draw_string_left(dpi, string_id, (void*)0x13CE952, 0, x + 4, y); + + // Nausea tolerance + y += 10; + int nausea_tolerance = peep->nausea_tolerance & 0x3; + RCT2_GLOBAL(0x13CE952, uint16) = nausea_tolerance + 2368; + gfx_draw_string_left(dpi, 1661, (void*)0x13CE952, 0, x, y); +} + +/* rct2: 0x006978F4 */ +void window_guest_rides_resize(){ + rct_window* w; + window_get_register(w); + + window_set_resize(w, 192, 128, 500, 400); +} + +/* rct2: 0x6977B0 */ +void window_guest_rides_update(){ + rct_window* w; + window_get_register(w); + + w->frame_no++; + + widget_invalidate(WC_PEEP, w->number, WIDX_TAB_2); + widget_invalidate(WC_PEEP, w->number, WIDX_TAB_3); + + rct_peep* peep = GET_PEEP(w->number); + + // Every 2048 ticks do a full window_invalidate + int number_of_ticks = RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, uint32) - peep->time_in_park; + if (!(number_of_ticks & 0x7FF)) window_invalidate(w); + + uint8 curr_list_position = 0; + for (uint8 ride_id = 0; ride_id < 255; ++ride_id){ + // Offset to the ride_id bit in peep_rides_been_on + uint8 ride_id_bit = ride_id & 0x3; + uint8 ride_id_offset = ride_id / 8; + if (peep->rides_been_on[ride_id_offset] & (1 << ride_id_bit)){ + rct_ride* ride = GET_RIDE(ride_id); + if (RCT2_ADDRESS(0x97C3AF, uint8)[ride->type] == 0){ + w->list_item_positions[curr_list_position] = ride_id; + curr_list_position++; + } + } + } + // If there are new items + if (w->no_list_items != curr_list_position){ + w->no_list_items = curr_list_position; + window_invalidate(w); + } +} + +/* rct2: 0x697844 */ +void window_guest_rides_tooltip(){ + RCT2_GLOBAL(0x013CE952, uint16) = STR_LIST; +} + +/* rct2: 0x69784E */ +void window_guest_rides_scroll_get_size(){ + rct_window *w; + + window_get_register(w); + + int height = w->no_list_items * 10; + + if (w->selected_list_item != -1){ + w->selected_list_item = -1; + window_invalidate(w); + } + + int visable_height = height + - window_guest_rides_widgets[WIDX_RIDE_SCROLL].bottom + + window_guest_rides_widgets[WIDX_RIDE_SCROLL].top + + 21; + + if (visable_height < 0) visable_height = 0; + + if (visable_height < w->scrolls[0].v_top){ + w->scrolls[0].v_top = visable_height; + window_invalidate(w); + } + +#ifdef _MSC_VER + __asm mov ecx, 0 +#else + __asm__("mov ecx, 0 "); +#endif + +#ifdef _MSC_VER + __asm mov edx, height +#else + __asm__("mov edx, %[height] " : [height] "+m" (height)); +#endif +} + +/* rct2: 0x006978CC */ +void window_guest_rides_scroll_mouse_down(){ + int index; + short x, y; + rct_window *w; + + window_scrollmouse_get_registers(w, x, y); + + index = y / 10; + if (index >= w->no_list_items) return; + + window_ride_main_open(w->list_item_positions[index]); +} + +/* rct2: 0x0069789C */ +void window_guest_rides_scroll_mouse_over(){ + int index; + short x, y; + rct_window *w; + + window_scrollmouse_get_registers(w, x, y); + + index = y / 10; + if (index >= w->no_list_items)return; + + if (index == w->selected_list_item)return; + w->selected_list_item = index; + + window_invalidate(w); +} + +/* rct2: 0x0069757A */ +void window_guest_rides_invalidate(){ + rct_window* w; + window_get_register(w); + if (window_guest_page_widgets[w->page] != w->widgets){ + w->widgets = window_guest_page_widgets[w->page]; + window_init_scroll_widgets(w); + } + + w->pressed_widgets |= 1ULL << (w->page + WIDX_TAB_1); + + rct_peep* peep = GET_PEEP(w->number); + RCT2_GLOBAL(0x13CE952, uint16) = peep->name_string_idx; + RCT2_GLOBAL(0x13CE954, uint32) = peep->id; + + window_guest_rides_widgets[WIDX_BACKGROUND].right = w->width - 1; + window_guest_rides_widgets[WIDX_BACKGROUND].bottom = w->height - 1; + + window_guest_rides_widgets[WIDX_PAGE_BACKGROUND].right = w->width - 1; + window_guest_rides_widgets[WIDX_PAGE_BACKGROUND].bottom = w->height - 1; + + window_guest_rides_widgets[WIDX_TITLE].right = w->width - 2; + + window_guest_rides_widgets[WIDX_CLOSE].left = w->width - 13; + window_guest_rides_widgets[WIDX_CLOSE].right = w->width - 3; + + window_guest_rides_widgets[WIDX_RIDE_SCROLL].right = w->width - 4; + window_guest_rides_widgets[WIDX_RIDE_SCROLL].bottom = w->height - 15; + + window_align_tabs(w, WIDX_TAB_1, WIDX_TAB_6); +} + +/* rct2: 0x00697637 */ +void window_guest_rides_paint(){ + rct_window *w; + rct_drawpixelinfo *dpi; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + window_guest_overview_tab_paint(w, dpi); + window_guest_stats_tab_paint(w, dpi); + window_guest_rides_tab_paint(w, dpi); + window_guest_finance_tab_paint(w, dpi); + window_guest_thoughts_tab_paint(w, dpi); + window_guest_inventory_tab_paint(w, dpi); + + rct_peep* peep = GET_PEEP(w->number); + + //cx + int x = w->x + window_guest_rides_widgets[WIDX_PAGE_BACKGROUND].left + 2; + //dx + int y = w->y + window_guest_rides_widgets[WIDX_PAGE_BACKGROUND].top + 2; + + gfx_draw_string_left(dpi, 2292, (void*)0, 0, x, y); + + y = w->y + window_guest_rides_widgets[WIDX_PAGE_BACKGROUND].bottom - 12; + + int ride_string_id = 3094; + int ride_string_arguments = 0; + if (peep->favourite_ride != 0xFF){ + rct_ride* ride = GET_RIDE(peep->favourite_ride); + ride_string_arguments = ride->name_arguments; + ride_string_id = ride->name; + } + RCT2_GLOBAL(0x13CE952, uint16) = ride_string_id; + RCT2_GLOBAL(0x13CE954, uint32) = ride_string_arguments; + + gfx_draw_string_left_clipped(dpi, 3093, (void*)0x13CE952, 0, x, y, w->width - 14); +} + +/* rct2: 0x006976FC */ +void window_guest_rides_scroll_paint(){ + rct_window *w; + rct_drawpixelinfo *dpi; + + window_paint_get_registers(w, dpi); + + // ax + int left = dpi->x; + // bx + int right = dpi->x + dpi->width - 1; + // cx + int top = dpi->y; + // dx + int bottom = dpi->y + dpi->height - 1; + + int colour = RCT2_ADDRESS(0x141FC48, uint8)[w->colours[1] * 8]; + gfx_fill_rect(dpi, left, top, right, bottom, colour); + + for (int list_index = 0; list_index < w->no_list_items; list_index++){ + int y = list_index * 10; + int string_format = 1191; + if (list_index == w->selected_list_item){ + gfx_fill_rect(dpi, 0, y, 800, y + 9, 0x2000031); + string_format = 1193; + } + rct_ride* ride = GET_RIDE(w->list_item_positions[list_index]); + + gfx_draw_string_left(dpi, string_format, (void*)&ride->name, 0, 0, y - 1); + } +} + +/* rct2: 0x00697C16 */ +void window_guest_finance_resize(){ + rct_window* w; + window_get_register(w); + + window_set_resize(w, 210, 134, 210, 134); +} + +/* rct2: 0x00697BF8 */ +void window_guest_finance_update(){ + rct_window* w; + window_get_register(w); + + w->frame_no++; + + widget_invalidate(WC_PEEP, w->number, WIDX_TAB_2); + widget_invalidate(WC_PEEP, w->number, WIDX_TAB_4); +} + +/* rct2: 0x00697968 */ +void window_guest_finance_invalidate(){ + rct_window* w; + window_get_register(w); + + if (window_guest_page_widgets[w->page] != w->widgets){ + w->widgets = window_guest_page_widgets[w->page]; + window_init_scroll_widgets(w); + } + + w->pressed_widgets |= 1ULL << (w->page + WIDX_TAB_1); + + rct_peep* peep = GET_PEEP(w->number); + + RCT2_GLOBAL(0x13CE952, uint16) = peep->name_string_idx; + RCT2_GLOBAL(0x13CE954, uint32) = peep->id; + + window_guest_finance_widgets[WIDX_BACKGROUND].right = w->width - 1; + window_guest_finance_widgets[WIDX_BACKGROUND].bottom = w->height - 1; + + window_guest_finance_widgets[WIDX_PAGE_BACKGROUND].right = w->width - 1; + window_guest_finance_widgets[WIDX_PAGE_BACKGROUND].bottom = w->height - 1; + + window_guest_finance_widgets[WIDX_TITLE].right = w->width - 2; + + window_guest_finance_widgets[WIDX_CLOSE].left = w->width - 13; + window_guest_finance_widgets[WIDX_CLOSE].right = w->width - 3; + + window_align_tabs(w, WIDX_TAB_1, WIDX_TAB_6); +} + +/* rct2: 0x00697A08 */ +void window_guest_finance_paint(){ + rct_window *w; + rct_drawpixelinfo *dpi; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + window_guest_overview_tab_paint(w, dpi); + window_guest_stats_tab_paint(w, dpi); + window_guest_rides_tab_paint(w, dpi); + window_guest_finance_tab_paint(w, dpi); + window_guest_thoughts_tab_paint(w, dpi); + window_guest_inventory_tab_paint(w, dpi); + + rct_peep* peep = GET_PEEP(w->number); + + //cx + int x = w->x + window_guest_finance_widgets[WIDX_PAGE_BACKGROUND].left + 4; + //dx + int y = w->y + window_guest_finance_widgets[WIDX_PAGE_BACKGROUND].top + 4; + + // Cash in pocket + RCT2_GLOBAL(0x13CE952, money32) = peep->cash_in_pocket; + gfx_draw_string_left(dpi, 1457, (void*)0x13CE952, 0, x, y); + + // Cash spent + y += 10; + RCT2_GLOBAL(0x13CE952, money32) = peep->cash_spent; + gfx_draw_string_left(dpi, 1456, (void*)0x13CE952, 0, x, y); + + y += 20; + gfx_fill_rect_inset(dpi, x, y - 6, x + 179, y - 5, w->colours[1], 32); + + // Paid to enter + RCT2_GLOBAL(0x13CE952, money32) = peep->paid_to_enter; + gfx_draw_string_left(dpi, 2296, (void*)0x13CE952, 0, x, y); + + // Paid on rides + y += 10; + RCT2_GLOBAL(0x13CE952, money32) = peep->paid_on_rides; + RCT2_GLOBAL(0x13CE956, uint16) = peep->no_of_rides; + if (peep->no_of_rides != 1){ + gfx_draw_string_left(dpi, 2298, (void*)0x13CE952, 0, x, y); + } + else{ + gfx_draw_string_left(dpi, 2297, (void*)0x13CE952, 0, x, y); + } + + // Paid on food + y += 10; + RCT2_GLOBAL(0x13CE952, money32) = peep->paid_on_food; + RCT2_GLOBAL(0x13CE956, uint16) = peep->no_of_food; + if (peep->no_of_food != 1){ + gfx_draw_string_left(dpi, 2300, (void*)0x13CE952, 0, x, y); + } + else{ + gfx_draw_string_left(dpi, 2299, (void*)0x13CE952, 0, x, y); + } + + // Paid on drinks + y += 10; + RCT2_GLOBAL(0x13CE952, money32) = peep->paid_on_drink; + RCT2_GLOBAL(0x13CE956, uint16) = peep->no_of_drinks; + if (peep->no_of_drinks != 1){ + gfx_draw_string_left(dpi, 2302, (void*)0x13CE952, 0, x, y); + } + else{ + gfx_draw_string_left(dpi, 2301, (void*)0x13CE952, 0, x, y); + } + + // Paid on souvenirs + y += 10; + RCT2_GLOBAL(0x13CE952, money32) = peep->paid_on_souvenirs; + RCT2_GLOBAL(0x13CE956, uint16) = peep->no_of_souvenirs; + if (peep->no_of_souvenirs != 1){ + gfx_draw_string_left(dpi, 2304, (void*)0x13CE952, 0, x, y); + } + else{ + gfx_draw_string_left(dpi, 2303, (void*)0x13CE952, 0, x, y); + } +} + +/* rct2: 0x00697E33 */ +void window_guest_thoughts_resize(){ + rct_window* w; + window_get_register(w); + + rct_peep* peep = GET_PEEP(w->number); + if (peep->var_45 & 1){ + peep->var_45 &=~(1 << 0); + window_invalidate(w); + } + + window_set_resize(w, 192, 159, 500, 450); +} + +/* rct2: 0x00697EB4 */ +void window_guest_thoughts_update(){ + rct_window* w; + window_get_register(w); + + w->frame_no++; + + widget_invalidate(WC_PEEP, w->number, WIDX_TAB_2); + widget_invalidate(WC_PEEP, w->number, WIDX_TAB_5); +} + +/* rct2: 0x00697C8A */ +void window_guest_thoughts_invalidate(){ + rct_window* w; + window_get_register(w); + + if (window_guest_page_widgets[w->page] != w->widgets){ + w->widgets = window_guest_page_widgets[w->page]; + window_init_scroll_widgets(w); + } + + w->pressed_widgets |= 1ULL << (w->page + WIDX_TAB_1); + + rct_peep* peep = GET_PEEP(w->number); + + RCT2_GLOBAL(0x13CE952, uint16) = peep->name_string_idx; + RCT2_GLOBAL(0x13CE954, uint32) = peep->id; + + window_guest_thoughts_widgets[WIDX_BACKGROUND].right = w->width - 1; + window_guest_thoughts_widgets[WIDX_BACKGROUND].bottom = w->height - 1; + + window_guest_thoughts_widgets[WIDX_PAGE_BACKGROUND].right = w->width - 1; + window_guest_thoughts_widgets[WIDX_PAGE_BACKGROUND].bottom = w->height - 1; + + window_guest_thoughts_widgets[WIDX_TITLE].right = w->width - 2; + + window_guest_thoughts_widgets[WIDX_CLOSE].left = w->width - 13; + window_guest_thoughts_widgets[WIDX_CLOSE].right = w->width - 3; + + window_align_tabs(w, WIDX_TAB_1, WIDX_TAB_6); +} + +/* rct2: 0x00697D2A */ +void window_guest_thoughts_paint(){ + rct_window *w; + rct_drawpixelinfo *dpi; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + window_guest_overview_tab_paint(w, dpi); + window_guest_stats_tab_paint(w, dpi); + window_guest_rides_tab_paint(w, dpi); + window_guest_finance_tab_paint(w, dpi); + window_guest_thoughts_tab_paint(w, dpi); + window_guest_inventory_tab_paint(w, dpi); + + rct_peep* peep = GET_PEEP(w->number); + + //cx + int x = w->x + window_guest_thoughts_widgets[WIDX_PAGE_BACKGROUND].left + 4; + //dx + int y = w->y + window_guest_thoughts_widgets[WIDX_PAGE_BACKGROUND].top + 4; + + gfx_draw_string_left(dpi, 1654, (void*)0, 0, x, y); + + y += 10; + for (rct_peep_thought* thought = peep->thoughts; thought < &peep->thoughts[PEEP_MAX_THOUGHTS]; ++thought){ + if (thought->type == PEEP_THOUGHT_TYPE_NONE) return; + if (thought->var_2 == 0) continue; + + uint32 argument1, argument2; + get_arguments_from_thought(*thought, &argument1, &argument2); + RCT2_GLOBAL(0x13CE952, uint32) = argument1; + RCT2_GLOBAL(0x13CE956, uint32) = argument2; + + int width = window_guest_thoughts_widgets[WIDX_PAGE_BACKGROUND].right + - window_guest_thoughts_widgets[WIDX_PAGE_BACKGROUND].left + - 8; + + y += gfx_draw_string_left_wrapped(dpi, (void*)0x13CE952, x, y, width, 1191, 0); + + // If this is the last visable line end drawing. + if (y > w->y + window_guest_thoughts_widgets[WIDX_PAGE_BACKGROUND].bottom - 32) return; + } +} + + +/* rct2: 0x00698294 */ +void window_guest_inventory_resize(){ + rct_window* w; + window_get_register(w); + + rct_peep* peep = GET_PEEP(w->number); + if (peep->var_45 & (1<<3)){ + peep->var_45 &= ~(1 << 3); + window_invalidate(w); + } + + window_set_resize(w, 192, 159, 500, 450); +} + +/* rct2: 0x00698315 */ +void window_guest_inventory_update(){ + rct_window* w; + window_get_register(w); + + w->frame_no++; + + widget_invalidate(WC_PEEP, w->number, WIDX_TAB_2); + widget_invalidate(WC_PEEP, w->number, WIDX_TAB_6); +} + +/* rct2: 0x00697EE1 */ +void window_guest_inventory_invalidate(){ + rct_window* w; + window_get_register(w); + + if (window_guest_page_widgets[w->page] != w->widgets){ + w->widgets = window_guest_page_widgets[w->page]; + window_init_scroll_widgets(w); + } + + w->pressed_widgets |= 1ULL << (w->page + WIDX_TAB_1); + + rct_peep* peep = GET_PEEP(w->number); + + RCT2_GLOBAL(0x13CE952, uint16) = peep->name_string_idx; + RCT2_GLOBAL(0x13CE954, uint32) = peep->id; + + window_guest_inventory_widgets[WIDX_BACKGROUND].right = w->width - 1; + window_guest_inventory_widgets[WIDX_BACKGROUND].bottom = w->height - 1; + + window_guest_inventory_widgets[WIDX_PAGE_BACKGROUND].right = w->width - 1; + window_guest_inventory_widgets[WIDX_PAGE_BACKGROUND].bottom = w->height - 1; + + window_guest_inventory_widgets[WIDX_TITLE].right = w->width - 2; + + window_guest_inventory_widgets[WIDX_CLOSE].left = w->width - 13; + window_guest_inventory_widgets[WIDX_CLOSE].right = w->width - 3; + + window_align_tabs(w, WIDX_TAB_1, WIDX_TAB_6); +} + +/* rct2: 0x00697F81 */ +void window_guest_inventory_paint(){ + rct_window *w; + rct_drawpixelinfo *dpi; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + window_guest_overview_tab_paint(w, dpi); + window_guest_stats_tab_paint(w, dpi); + window_guest_rides_tab_paint(w, dpi); + window_guest_finance_tab_paint(w, dpi); + window_guest_thoughts_tab_paint(w, dpi); + window_guest_inventory_tab_paint(w, dpi); + + rct_peep* peep = GET_PEEP(w->number); + + //cx + int x = w->x + window_guest_inventory_widgets[WIDX_PAGE_BACKGROUND].left + 4; + //dx + int y = w->y + window_guest_inventory_widgets[WIDX_PAGE_BACKGROUND].top + 2; + + int max_y = w->y + w->height - 22; + int no_items = 0; + + gfx_draw_string_left(dpi, 1810, (void*)0, 0, x, y); + + y += 10; + + for (int i = 0; y < max_y && i < 28; ++i){ + int item_flag = 1 << i; + if (!(peep->item_standard_flags & item_flag))continue; + no_items++; + + RCT2_GLOBAL(0x13CE952, uint32) = 5061 + i; + + switch (item_flag){ + case PEEP_ITEM_TSHIRT: + RCT2_GLOBAL(0x13CE952, uint32) |= 0x20000000 | peep->tshirt_colour << 19; + break; + case PEEP_ITEM_HAT: + RCT2_GLOBAL(0x13CE952, uint32) |= 0x20000000 | peep->hat_colour << 19; + break; + case PEEP_ITEM_BALLOON: + RCT2_GLOBAL(0x13CE952, uint32) |= 0x20000000 | peep->balloon_colour << 19; + break; + case PEEP_ITEM_UMBRELLA: + RCT2_GLOBAL(0x13CE952, uint32) |= 0x20000000 | peep->umbrella_colour << 19; + break; + } + + int string_format = 2072 + i; + if (string_format >= 2104) string_format += 84; //??? i is never 32 + + RCT2_GLOBAL(0x13CE956, uint16) = string_format; + RCT2_GLOBAL(0x13CE958, uint16) = RCT2_GLOBAL(0x13573D4, uint16); + RCT2_GLOBAL(0x13CE95A, uint32) = RCT2_GLOBAL(0x13573D8, uint32); + rct_ride* ride; + + switch (item_flag){ + case PEEP_ITEM_PHOTO: + ride = GET_RIDE(peep->photo1_ride_ref); + RCT2_GLOBAL(0x13CE958, uint16) = ride->name; + RCT2_GLOBAL(0x13CE95A, uint32) = ride->name_arguments; + break; + case PEEP_ITEM_VOUCHER: + RCT2_GLOBAL(0x13CE958, uint16) = peep->voucher_type + 2418; + RCT2_GLOBAL(0x13CE95A, uint16) = RCT2_GLOBAL(0x13573D4, uint16); + RCT2_GLOBAL(0x13CE95C, uint32) = RCT2_GLOBAL(0x13573D8, uint32); + + if (peep->voucher_type == VOUCHER_TYPE_PARK_ENTRY_FREE || peep->voucher_type == VOUCHER_TYPE_PARK_ENTRY_HALF_PRICE)break; + + int voucher_id = peep->voucher_arguments + 1988; + if (voucher_id >= 2020) voucher_id += 102; + + RCT2_GLOBAL(0x13CE95A, uint16) = voucher_id; + + if (peep->voucher_type == VOUCHER_TYPE_FOOD_OR_DRINK_FREE)break; + ride = GET_RIDE(peep->voucher_arguments); + RCT2_GLOBAL(0x13CE95A, uint16) = ride->name; + RCT2_GLOBAL(0x13CE95C, uint32) = ride->name_arguments; + break; + } + + int width = window_guest_inventory_widgets[WIDX_PAGE_BACKGROUND].right + - window_guest_inventory_widgets[WIDX_PAGE_BACKGROUND].left + - 8; + + y += gfx_draw_string_left_wrapped(dpi, (void*)0x13CE952, x, y, width, 1875, 0); + } + + for (int i = 0; y < max_y && i < 22; ++i){ + int item_flag = 1 << i; + + if (!(peep->item_extra_flags & item_flag))continue; + no_items++; + + RCT2_GLOBAL(0x13CE952, uint32) = 5089 + i; + RCT2_GLOBAL(0x13CE956, uint16) = 2188; + RCT2_GLOBAL(0x13CE958, uint16) = RCT2_GLOBAL(0x13573D4, uint16); + RCT2_GLOBAL(0x13CE95A, uint32) = RCT2_GLOBAL(0x13573D8, uint32); + + if (i < 3){ + int ride_id = 0; + switch (item_flag){ + case PEEP_ITEM_PHOTO2: + ride_id = peep->photo2_ride_ref; + break; + case PEEP_ITEM_PHOTO3: + ride_id = peep->photo3_ride_ref; + break; + case PEEP_ITEM_PHOTO4: + ride_id = peep->photo4_ride_ref; + break; + } + + rct_ride* ride = GET_RIDE(ride_id); + RCT2_GLOBAL(0x13CE958, uint16) = ride->name; + RCT2_GLOBAL(0x13CE95A, uint32) = ride->name_arguments; + } + + int width = window_guest_inventory_widgets[WIDX_PAGE_BACKGROUND].right + - window_guest_inventory_widgets[WIDX_PAGE_BACKGROUND].left + - 8; + + y += gfx_draw_string_left_wrapped(dpi, (void*)0x13CE952, x, y, width, 1875, 0); + } + + if (!no_items){ + gfx_draw_string_left(dpi, 2293, (void*)0, 0, x, y); + } +} diff --git a/src/window_guest_list.c b/src/windows/guest_list.c similarity index 91% rename from src/window_guest_list.c rename to src/windows/guest_list.c index 217e7ebb26..733256c688 100644 --- a/src/window_guest_list.c +++ b/src/windows/guest_list.c @@ -20,16 +20,16 @@ #include #include -#include "addresses.h" -#include "game.h" -#include "peep.h" -#include "string_ids.h" -#include "sprite.h" -#include "sprites.h" -#include "ride.h" -#include "widget.h" -#include "window.h" -#include "window_dropdown.h" +#include "../addresses.h" +#include "../game.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../localisation/localisation.h" +#include "../peep/peep.h" +#include "../ride/ride.h" +#include "../sprites.h" +#include "../world/sprite.h" +#include "dropdown.h" enum { PAGE_INDIVIDUAL, @@ -132,8 +132,7 @@ static uint8 _window_guest_list_groups_guest_faces[240 * 58]; static int window_guest_list_is_peep_in_filter(rct_peep* peep); static void window_guest_list_find_groups(); -static int get_guest_face_sprite_small(rct_peep *peep); -static int get_guest_face_sprite_large(rct_peep *peep); + static void get_arguments_from_peep(rct_peep *peep, uint32 *argument_1, uint32* argument_2); /** @@ -427,7 +426,7 @@ static void window_guest_list_scrollmousedown() if (i == 0) { // Open guest window - window_peep_open(peep); + window_guest_open(peep); break; } else { @@ -626,7 +625,7 @@ static void window_guest_list_scrollpaint() switch (_window_guest_list_selected_view) { case VIEW_ACTIONS: // Guest face - gfx_draw_sprite(dpi, get_guest_face_sprite_small(peep), 118, y, 0); + gfx_draw_sprite(dpi, get_peep_face_sprite_small(peep), 118, y, 0); // Tracking icon if (peep->flags & PEEP_FLAGS_TRACKING) @@ -802,7 +801,7 @@ static void window_guest_list_find_groups() RCT2_ADDRESS(0x00F1AF26, uint8)[groupIndex] = groupIndex; faceIndex = groupIndex * 56; - _window_guest_list_groups_guest_faces[faceIndex++] = get_guest_face_sprite_small(peep) - 5486; + _window_guest_list_groups_guest_faces[faceIndex++] = get_peep_face_sprite_small(peep) - 5486; // Find more peeps that belong to same group FOR_ALL_GUESTS(spriteIndex2, peep2) { @@ -822,7 +821,7 @@ static void window_guest_list_find_groups() // Add face sprite, cap at 56 though if (_window_guest_list_groups_num_guests[groupIndex] >= 56) continue; - _window_guest_list_groups_guest_faces[faceIndex++] = get_guest_face_sprite_small(peep2) - 5486; + _window_guest_list_groups_guest_faces[faceIndex++] = get_peep_face_sprite_small(peep2) - 5486; } if (RCT2_GLOBAL(0x00F1EDF6, uint16) == 0) { @@ -872,75 +871,4 @@ static void window_guest_list_find_groups() nextPeep: ; } -} - -/** - * Function split into large and small sprite - * rct2: 0x00698721 - */ -static int get_guest_face_sprite_small(rct_peep *peep) -{ - int sprite; - sprite = SPR_PEEP_SMALL_FACE_ANGRY; - - if (peep->var_F3) return sprite; - sprite = SPR_PEEP_SMALL_FACE_VERY_VERY_SICK; - - if (peep->nausea > 200) return sprite; - sprite--; //VERY_SICK - - if (peep->nausea > 170) return sprite; - sprite--; //SICK - - if (peep->nausea > 140) return sprite; - sprite = SPR_PEEP_SMALL_FACE_VERY_TIRED; - - if (peep->energy < 46) return sprite; - sprite--; //TIRED - - if (peep->energy < 70) return sprite; - sprite = SPR_PEEP_SMALL_FACE_VERY_VERY_UNHAPPY; - - //There are 7 different happiness based faces - for (int i = 37; peep->happiness >= i; i += 37) - { - sprite++; - } - - return sprite; -} - -/** -* Function split into large and small sprite -* rct2: 0x00698721 -*/ -static int get_guest_face_sprite_large(rct_peep* peep){ - int sprite; - sprite = SPR_PEEP_LARGE_FACE_ANGRY; - - if (peep->var_F3) return sprite; - sprite = SPR_PEEP_LARGE_FACE_VERY_VERY_SICK; - - if (peep->nausea > 200) return sprite; - sprite = SPR_PEEP_LARGE_FACE_VERY_SICK; - - if (peep->nausea > 170) return sprite; - sprite = SPR_PEEP_LARGE_FACE_SICK; - - if (peep->nausea > 140) return sprite; - sprite = SPR_PEEP_LARGE_FACE_VERY_TIRED; - - if (peep->energy < 46) return sprite; - sprite--; //TIRED - - if (peep->energy < 70) return sprite; - sprite = SPR_PEEP_LARGE_FACE_VERY_VERY_UNHAPPY; - - //There are 7 different happiness based faces - for (int i = 37; peep->happiness >= i; i += 37) - { - sprite++; - } - - return sprite; -} +} \ No newline at end of file diff --git a/src/window_land.c b/src/windows/land.c similarity index 98% rename from src/window_land.c rename to src/windows/land.c index 81d95020b1..cccbe99d7a 100644 --- a/src/window_land.c +++ b/src/windows/land.c @@ -18,13 +18,13 @@ * along with this program. If not, see . *****************************************************************************/ -#include "addresses.h" -#include "map.h" -#include "string_ids.h" -#include "sprites.h" -#include "widget.h" -#include "window.h" -#include "window_dropdown.h" +#include "../addresses.h" +#include "../world/map.h" +#include "../localisation/localisation.h" +#include "../sprites.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "dropdown.h" enum WINDOW_LAND_WIDGET_IDX { WIDX_BACKGROUND, diff --git a/src/window_main.c b/src/windows/main.c similarity index 95% rename from src/window_main.c rename to src/windows/main.c index 7f2e6f3caa..1134af7f65 100644 --- a/src/window_main.c +++ b/src/windows/main.c @@ -18,10 +18,10 @@ * along with this program. If not, see . *****************************************************************************/ -#include "addresses.h" -#include "viewport.h" -#include "widget.h" -#include "window.h" +#include "../addresses.h" +#include "../interface/viewport.h" +#include "../interface/widget.h" +#include "../interface/window.h" rct_widget window_main_widgets[] = { { WWT_VIEWPORT, 0, 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0xFFFFFFFE, 0xFFFF }, diff --git a/src/window_map.c b/src/windows/map.c similarity index 80% rename from src/window_map.c rename to src/windows/map.c index 9ac0b2e380..2bbf64b06e 100644 --- a/src/window_map.c +++ b/src/windows/map.c @@ -19,11 +19,13 @@ *****************************************************************************/ #include -#include "addresses.h" -#include "sprites.h" -#include "string_ids.h" -#include "widget.h" -#include "window.h" +#include "../addresses.h" +#include "../sprites.h" +#include "../localisation/localisation.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../windows/scenery.h" +#include "../interface/viewport.h" enum WINDOW_MAP_WIDGET_IDX { WIDX_BACKGROUND, @@ -84,6 +86,9 @@ static void window_map_scrollmousedown(); static void window_map_invalidate(); static void window_map_paint(); static void window_map_scrollpaint(); +static void window_map_tooltip(); + +static void window_map_set_bounds(rct_window* w); static void window_map_init_map(); static void sub_68C990(); @@ -111,7 +116,7 @@ static void* window_map_events[] = { window_map_emptysub, window_map_emptysub, window_map_emptysub, - (void*)0x0068D140, + window_map_tooltip, window_map_emptysub, window_map_emptysub, window_map_invalidate, @@ -160,8 +165,10 @@ void window_map_open() (1 << WIDX_ROTATE_90) | (1 << WIDX_PEOPLE_STARTING_POSITION); w->var_020 |= 0x300; - window_init_scroll_widgets(w); + + window_map_set_bounds(w); + w->map.rotation = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint16); window_map_init_map(); @@ -196,28 +203,133 @@ static void window_map_close() */ static void window_map_mouseup() { - RCT2_CALLPROC_EBPSAFE(0x0068CFC1); - /*short widgetIndex; - rct_window *w; + //RCT2_CALLPROC_EBPSAFE(0x0068CFC1); + sint16 var_idx; + rct_window* var_w; - #ifdef _MSC_VER - __asm mov widgetIndex, dx - #else - __asm__ ( "mov %[widgetIndex], dx " : [widgetIndex] "+m" (widgetIndex) ); - #endif - - #ifdef _MSC_VER - __asm mov w, esi - #else - __asm__ ( "mov %[w], esi " : [w] "+m" (w) ); - #endif - - - switch (widgetIndex) { + window_widget_get_registers(var_w, var_idx); + + switch (var_idx) + { case WIDX_CLOSE: - window_close(w); + window_close(var_w); break; - }*/ + + case WIDX_SET_LAND_RIGHTS: + window_invalidate(var_w); + if (!tool_set(var_w, var_idx, 2)) // jb nullsub_52 + break; + + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = 1; + RCT2_GLOBAL(0xF1AD61, sint8) = 2; + show_gridlines(); + show_land_rights(); + show_construction_rights(); + break; + + case WIDX_LAND_OWNED_CHECKBOX: + RCT2_GLOBAL(0xF1AD61, sint8) ^= 2; + + if (RCT2_GLOBAL(0xF1AD61, sint8) & 2) + RCT2_GLOBAL(0xF1AD61, sint8) &= 0xF2; + + window_invalidate(var_w); + break; + + case WIDX_LAND_SALE_CHECKBOX: + RCT2_GLOBAL(0xF1AD61, sint8) ^= 8; + + if (RCT2_GLOBAL(0xF1AD61, sint8) & 8) + RCT2_GLOBAL(0xF1AD61, sint8) &= 0xF8; + + window_invalidate(var_w); + break; + + case WIDX_CONSTRUCTION_RIGHTS_OWNED_CHECKBOX: + RCT2_GLOBAL(0xF1AD61, sint8) ^= 1; + + if (RCT2_GLOBAL(0xF1AD61, sint8) & 1) + RCT2_GLOBAL(0xF1AD61, sint8) &= 0xF1; + + window_invalidate(var_w); + break; + + case WIDX_CONSTRUCTION_RIGHTS_SALE_CHECKBOX: + RCT2_GLOBAL(0xF1AD61, sint8) ^= 4; + + if (RCT2_GLOBAL(0xF1AD61, sint8) & 4) + RCT2_GLOBAL(0xF1AD61, sint8) &= 0xF4; + + window_invalidate(var_w); + break; + + case WIDX_LAND_TOOL_SMALLER: + --RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16); + + if (RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) < 1) + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = 1; + + window_invalidate(var_w); + break; + + case WIDX_LAND_TOOL_LARGER: + ++RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16); + + if (RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) > 7) + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = 7; + + window_invalidate(var_w); + break; + + case WIDX_BUILD_PARK_ENTRANCE: + window_invalidate(var_w); + if (!tool_set(var_w, var_idx, 2)) // jb nullsub_52 + break; + + RCT2_GLOBAL(0x9E32D2, sint8) = 0; + + if (!(RCT2_GLOBAL(0x9DE518, sint32) & (1 << 6))) // Remove? + RCT2_GLOBAL(0x9DE518, sint32) |= (1 << 6); + + show_gridlines(); + show_land_rights(); + show_construction_rights(); + break; + + case WIDX_ROTATE_90: + ++window_scenery_rotation; + window_scenery_rotation &= 3; + break; + + case WIDX_PEOPLE_STARTING_POSITION: + if (!tool_set(var_w, var_idx, 2)) // jb nullsub_52 + break; + + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = 0; + + if (RCT2_GLOBAL(RCT2_ADDRESS_PEEP_SPAWNS, sint16) != -1 && RCT2_GLOBAL(0x13573F8, sint16) != -1) + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = 1; + + show_gridlines(); + show_land_rights(); + show_construction_rights(); + break; + + default: + if (var_idx >= WIDX_PEOPLE_TAB && var_idx <= WIDX_RIDES_TAB) + { + var_idx -= WIDX_PEOPLE_TAB; + if (var_idx == var_w->selected_tab) + break; + + var_w->selected_tab = var_idx; + var_w->list_information_type = 0; + } + break; + + } + + return; } /** @@ -226,7 +338,14 @@ static void window_map_mouseup() */ static void window_map_mousedown(int widgetIndex, rct_window*w, rct_widget* widget) { - RCT2_CALLPROC_EBPSAFE(0x0068D040); + // The normal map window doesn't have widget 8 or 9. + // I assume these widgets refer to the Scenario Editor's map window. + if (widgetIndex == 8) { + RCT2_CALLPROC_EBPSAFE(0x0068D641); + } + else if (widgetIndex == 9) { + RCT2_CALLPROC_EBPSAFE(0x0068D6B4); + } } /** @@ -452,6 +571,15 @@ static void window_map_paint() gfx_draw_string_left(dpi, STR_MAP_SIZE, 0, 0, w->x + 4, w->y + w->widgets[WIDX_MAP_SIZE_SPINNER].top + 1); } +/* +* +* rct2: 0x0068D140 +*/ +static void window_map_tooltip() +{ + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, short) = 0xC55; +} + /** * * rct2: 0x0068CF23 @@ -547,4 +675,17 @@ static void sub_68C990() w_map->scrolls[0].h_left = cx; w_map->scrolls[0].v_top = dx; widget_scroll_update_thumbs(w, WIDX_MAP); +} + +/** +* ref. by: window_map_scrollmousedown +* rct2: 0x0068D7DC +*/ +void window_map_set_bounds(rct_window* w) +{ + w->flags |= WF_RESIZABLE; // (1 << 8) + w->min_width = 245; + w->max_width = 800; + w->min_height = 259; + w->max_height = 560; } \ No newline at end of file diff --git a/src/windows/music_credits.c b/src/windows/music_credits.c new file mode 100644 index 0000000000..8910bb577f --- /dev/null +++ b/src/windows/music_credits.c @@ -0,0 +1,201 @@ +/***************************************************************************** +* Copyright (c) 2014 Ted John +* OpenRCT2, an open source clone of Roller Coaster Tycoon 2. +* +* This file is part of OpenRCT2. +* +* OpenRCT2 is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. + +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. + +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*****************************************************************************/ + +#include +#include +#include "../addresses.h" +#include "../localisation/localisation.h" +#include "../sprites.h" +#include "../interface/widget.h" +#include "../interface/window.h" + +enum WINDOW_MUSIC_CREDITS_WIDGET_IDX { + WIDX_BACKGROUND, + WIDX_TITLE, + WIDX_CLOSE +}; + +rct_widget window_music_credits_widgets[] = { + { WWT_FRAME, 0, 0, 509, 0, 313, 0x0FFFFFFFF, STR_NONE }, // panel / background + { WWT_CAPTION, 0, 1, 508, 1, 14, STR_MUSIC_ACKNOWLEDGEMENTS, STR_WINDOW_TITLE_TIP }, // title bar + { WWT_CLOSEBOX, 0, 497, 507, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, // close x button + { WWT_SCROLL, 0, 4, 505, 18, 309, 2, STR_NONE }, // scroll + { WIDGETS_END }, +}; + +static void window_music_credits_emptysub() { } +static void window_music_credits_mouseup(); +static void window_music_credits_scrollgetsize(); +static void window_music_credits_paint(); +static void window_music_credits_scrollpaint(); + +static void* window_music_credits_events[] = { + window_music_credits_emptysub, + window_music_credits_mouseup, + window_music_credits_emptysub, + window_music_credits_emptysub, + window_music_credits_emptysub, + window_music_credits_emptysub, + window_music_credits_emptysub, + window_music_credits_emptysub, + window_music_credits_emptysub, + window_music_credits_emptysub, + window_music_credits_emptysub, + window_music_credits_emptysub, + window_music_credits_emptysub, + window_music_credits_emptysub, + window_music_credits_emptysub, + window_music_credits_scrollgetsize, + window_music_credits_emptysub, + window_music_credits_emptysub, + window_music_credits_emptysub, + window_music_credits_emptysub, + window_music_credits_emptysub, + window_music_credits_emptysub, + window_music_credits_emptysub, + window_music_credits_emptysub, + window_music_credits_emptysub, + window_music_credits_emptysub, + window_music_credits_paint, + window_music_credits_scrollpaint +}; + +/** +* +* rct2: 0x0066D55B +*/ +void window_music_credits_open() +{ + rct_window* window; + + // Check if window is already open + window = window_bring_to_front_by_id(WC_MUSIC_CREDITS, 0); + if (window != NULL) + return; + + window = window_create( + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) / 2 - 255, + max(28, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) / 2 - 157), + 510, + 314, + (uint32*)window_music_credits_events, + WC_MUSIC_CREDITS, + 0 + ); + + window->widgets = window_music_credits_widgets; + window->enabled_widgets = 1 << WIDX_CLOSE; + + window_init_scroll_widgets(window); + window->colours[0] = 7; + window->colours[1] = 7; + window->colours[2] = 7; + +} + +/** +* +* rct2: 0x0066DB2C +*/ +static void window_music_credits_mouseup() +{ + short widgetIndex; + rct_window *w; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + } +} + +/** + * + * rct2: 0x0066DB37 + */ +static void window_music_credits_scrollgetsize() +{ + int y = 560; + + #ifdef _MSC_VER + __asm mov edx, y + #else + __asm__("mov edx, %[y] " : [y] "+m" (y)); + #endif +} + +/** +* +* rct2: 0x0066D7B9 +*/ +static void window_music_credits_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); +} + +/** + * + * rct2: 0x0066D7BF + */ +static void window_music_credits_scrollpaint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + window_paint_get_registers(w, dpi); + + int x = 245; + + int y = 2; + int string = 0xB30; + for (int i = 0; i < 12; i++) { + gfx_draw_string_centred(dpi, string, x, y, 0, 0); + y += 10; + if (i == 10) { // Add 4 more space before "Original recordings ...". + y += 4; + } + string += 1; + } + + // Draw the separator + y += 5; + gfx_fill_rect_inset(dpi, 4, y, 484, y+1, w->colours[1], 0x20); + y += 11; + + for (int i = 0; i < 31; i++) { + if (i == 21) { // Move special courtesy to below Hypothermia. + gfx_draw_string_centred(dpi, string + 4, x, y, 0, 0); + y += 10; + continue; + } else if (i == 25) { // Remove special courtesy and blank line. + string += 2; + } + gfx_draw_string_centred(dpi, string, x, y, 0, 0); + y += 10; + string += 1; + } + +} \ No newline at end of file diff --git a/src/window_new_campaign.c b/src/windows/new_campaign.c similarity index 98% rename from src/window_new_campaign.c rename to src/windows/new_campaign.c index 39ad693d98..d2146ad9e9 100644 --- a/src/window_new_campaign.c +++ b/src/windows/new_campaign.c @@ -19,14 +19,14 @@ *****************************************************************************/ #include -#include "addresses.h" -#include "game.h" -#include "marketing.h" -#include "ride.h" -#include "string_ids.h" -#include "widget.h" -#include "window.h" -#include "window_dropdown.h" +#include "../addresses.h" +#include "../game.h" +#include "../localisation/localisation.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../management/marketing.h" +#include "../ride/ride.h" +#include "dropdown.h" #define SELECTED_RIDE_UNDEFINED ((uint16)0xFFFF) diff --git a/src/window_new_ride.c b/src/windows/new_ride.c similarity index 93% rename from src/window_new_ride.c rename to src/windows/new_ride.c index 0c8585f1ab..8c6589ec60 100644 --- a/src/window_new_ride.c +++ b/src/windows/new_ride.c @@ -19,24 +19,19 @@ *****************************************************************************/ #include -#include "addresses.h" -#include "audio.h" -#include "game.h" -#include "news_item.h" -#include "ride.h" -#include "string_ids.h" -#include "scenery.h" -#include "track.h" -#include "widget.h" -#include "window.h" +#include "../addresses.h" +#include "../audio/audio.h" +#include "../game.h" +#include "../management/news_item.h" +#include "../ride/ride.h" +#include "../localisation/localisation.h" +#include "../world/scenery.h" +#include "../ride/track.h" +#include "../interface/widget.h" +#include "../interface/window.h" #define _window_new_ride_current_tab RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_RIDE_LIST_SELECTED_TAB, uint8) -typedef struct { - uint8 type; - uint8 entry_index; -} ride_list_item; - #pragma region Ride type view order /** @@ -247,6 +242,7 @@ static void* window_new_ride_events[] = { const int window_new_ride_tab_animation_loops[] = { 20, 32, 10, 72, 24, 28, 16 }; const int window_new_ride_tab_animation_divisor[] = { 4, 8, 2, 4, 4, 4, 2 }; +static void window_new_ride_set_page(rct_window *w, int page); static void window_new_ride_refresh_widget_sizing(rct_window *w); static ride_list_item window_new_ride_scroll_get_ride_list_item_at(rct_window *w, int x, int y); static void window_new_ride_paint_ride_information(rct_window *w, rct_drawpixelinfo *dpi, ride_list_item item, int x, int y, int width); @@ -279,19 +275,6 @@ void window_new_ride_init_vars() { RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_RIDE_LIST_INFORMATION_TYPE, uint8) = 0; } -uint8 *get_ride_entry_indices_for_ride_type(uint8 rideType) -{ - uint8 *typeToRideEntryIndexMap = (uint8*)0x009E32F8; - uint8 *entryIndexList = typeToRideEntryIndexMap; - while (rideType > 0) { - do { - entryIndexList++; - } while (*(entryIndexList - 1) != 255); - rideType--; - } - return entryIndexList; -} - /** * * rct2: 0x006B6F3E @@ -446,6 +429,52 @@ void window_new_ride_open() window_new_ride_scroll_to_focused_ride(w); } +/** + * + * rct2: 0x006B3EBA + */ +void window_new_ride_focus(ride_list_item rideItem) +{ + rct_window *w; + rct_ride_type *rideType; + + w = window_find_by_id(WC_CONSTRUCT_RIDE, 0); + if (w == NULL) + return; + + rideType = GET_RIDE_ENTRY(rideItem.entry_index); + window_new_ride_set_page(w, rideType->category[0]); + + ride_list_item *listItem = (ride_list_item*)0x00F43523; + while (listItem->type != RIDE_TYPE_NULL) { + if (listItem->type == rideItem.type && listItem->entry_index == rideItem.type) { + RCT2_GLOBAL(0x00F43825, uint8) = rideItem.type; + RCT2_GLOBAL(0x00F43826, uint8) = rideItem.entry_index; + w->new_ride.highlighted_ride_id = (rideItem.entry_index << 8) | rideItem.type; + window_new_ride_scroll_to_focused_ride(w); + } + listItem++; + } +} + +static void window_new_ride_set_page(rct_window *w, int page) +{ + _window_new_ride_current_tab = page; + w->frame_no = 0; + w->new_ride.highlighted_ride_id = -1; + w->new_ride.selected_ride_countdown = -1; + window_new_ride_populate_list(); + if (page < WINDOW_NEW_RIDE_PAGE_RESEARCH) { + w->new_ride.highlighted_ride_id = RCT2_ADDRESS(RCT2_ADDRESS_WINDOW_RIDE_LIST_HIGHLIGHTED_ITEM, sint16)[page]; + if (w->new_ride.highlighted_ride_id == -1) + w->new_ride.highlighted_ride_id = RCT2_GLOBAL(0x00F43523, sint16); + } + + window_new_ride_refresh_widget_sizing(w); + window_invalidate(w); + window_new_ride_scroll_to_focused_ride(w); +} + /** * * rct2: 0x006B3DF1 @@ -568,26 +597,8 @@ static void window_new_ride_mouseup() */ static void window_new_ride_mousedown(int widgetIndex, rct_window *w, rct_widget *widget) { - int page; - if (widgetIndex < WIDX_TAB_1 || widgetIndex > WIDX_TAB_7) - return; - - page = widgetIndex - WIDX_TAB_1; - - _window_new_ride_current_tab = page; - w->frame_no = 0; - w->new_ride.highlighted_ride_id = -1; - w->new_ride.selected_ride_countdown = -1; - window_new_ride_populate_list(); - if (page < WINDOW_NEW_RIDE_PAGE_RESEARCH) { - w->new_ride.highlighted_ride_id = RCT2_ADDRESS(RCT2_ADDRESS_WINDOW_RIDE_LIST_HIGHLIGHTED_ITEM, sint16)[page]; - if (w->new_ride.highlighted_ride_id == -1) - w->new_ride.highlighted_ride_id = RCT2_GLOBAL(0x00F43523, sint16); - } - - window_new_ride_refresh_widget_sizing(w); - window_invalidate(w); - window_new_ride_scroll_to_focused_ride(w); + if (widgetIndex >= WIDX_TAB_1 && widgetIndex <= WIDX_TAB_7) + window_new_ride_set_page(w, widgetIndex - WIDX_TAB_1); } /** @@ -658,7 +669,7 @@ static void window_new_ride_scrollmousedown() RCT2_ADDRESS(RCT2_ADDRESS_WINDOW_RIDE_LIST_HIGHLIGHTED_ITEM, ride_list_item)[_window_new_ride_current_tab] = item; w->new_ride.selected_ride_id = *((sint16*)&item); - sound_play_panned(SOUND_CLICK_1, w->x + (w->width / 2)); + sound_play_panned(SOUND_CLICK_1, w->x + (w->width / 2), 0, 0, 0); w->new_ride.selected_ride_countdown = 8; window_invalidate(w); } @@ -753,9 +764,9 @@ static void window_new_ride_paint() // Research type rct_string_id stringId = STR_RESEARCH_UNKNOWN; if (RCT2_GLOBAL(0x01357CF3, uint8) != 0) { - stringId = STR_TRANSPORT_RIDE + RCT2_GLOBAL(0x013580E6, uint8); + stringId = STR_TRANSPORT_RIDE + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_CATEGORY, uint8); if (RCT2_GLOBAL(0x01357CF3, uint8) != 1) { - uint32 typeId = RCT2_GLOBAL(0x013580E0, uint32); + uint32 typeId = RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_ITEM, uint32); if (typeId >= 0x10000) { rct_ride_type *rideEntry = RCT2_GLOBAL(0x009ACFA4 + (typeId & 0xFF) * 4, rct_ride_type*); stringId = rideEntry->var_008 & 0x1000 ? @@ -791,16 +802,20 @@ static void window_new_ride_paint() y = w->y + window_new_ride_widgets[WIDX_LAST_DEVELOPMENT_GROUP].top + 12; uint32 typeId = RCT2_GLOBAL(RCT2_ADDRESS_LAST_RESEARCHED_ITEM_SUBJECT, uint32); + int lastDevelopmentFormat; if (typeId != 0xFFFFFFFF) { if (typeId >= 0x10000) { rct_ride_type *rideEntry = RCT2_GLOBAL(0x009ACFA4 + (typeId & 0xFF) * 4, rct_ride_type*); stringId = rideEntry->var_008 & 0x1000 ? rideEntry->name : - (typeId & 0xFF00) + 2; + ((typeId >> 8) & 0xFF) + 2; + + lastDevelopmentFormat = STR_RESEARCH_RIDE_LABEL; } else { stringId = g_scenerySetEntries[typeId]->name; + lastDevelopmentFormat = STR_RESEARCH_SCENERY_LABEL; } - gfx_draw_string_left_wrapped(dpi, &stringId, x, y, 266, STR_RESEARCH_RIDE_LABEL, 0); + gfx_draw_string_left_wrapped(dpi, &stringId, x, y, 266, lastDevelopmentFormat, 0); } } @@ -870,7 +885,7 @@ static ride_list_item window_new_ride_scroll_get_ride_list_item_at(rct_window *w int column = x / 116; int row = y / 116; - if (row >= 5) + if (column >= 5) return result; int index = column + (row * 5); @@ -887,7 +902,7 @@ static ride_list_item window_new_ride_scroll_get_ride_list_item_at(rct_window *w static int get_num_track_designs(ride_list_item item) { - track_load_list(*((uint16*)&item)); + track_load_list(item); uint8 *trackDesignList = (uint8*)0x00F441EC; int count = 0; @@ -977,17 +992,14 @@ static void window_new_ride_select(rct_window *w) uint32 rideTypeFlags = RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (item.type * 8), uint32); if (rideTypeFlags & 0x10000000) { - track_load_list(*((sint16*)&item)); + track_load_list(item); uint8 *trackDesignList = (uint8*)0x00F441EC; if (*trackDesignList != 0) { - // Show track design list - RCT2_CALLPROC_X(0x006CF1A2, *((sint16*)&item), 0, 0, 0, 0, 0, 0); + window_track_list_open(item); return; } } - // Show ride construction window - //RCT2_CALLPROC_X(0x006B4800, *((sint16*)&item), 0, 0, 0, 0, 0, 0); - ride_construct_new(*((sint16*)&item)); + ride_construct_new(item); } diff --git a/src/window_news.c b/src/windows/news.c similarity index 95% rename from src/window_news.c rename to src/windows/news.c index 9c431422e4..1f7a85b27d 100644 --- a/src/window_news.c +++ b/src/windows/news.c @@ -19,14 +19,14 @@ *****************************************************************************/ #include -#include "addresses.h" -#include "audio.h" -#include "news_item.h" -#include "string_ids.h" -#include "sprite.h" -#include "sprites.h" -#include "widget.h" -#include "window.h" +#include "../addresses.h" +#include "../audio/audio.h" +#include "../management/news_item.h" +#include "../localisation/localisation.h" +#include "../world/sprite.h" +#include "../sprites.h" +#include "../interface/widget.h" +#include "../interface/window.h" enum WINDOW_NEWS_WIDGET_IDX { WIDX_BACKGROUND, @@ -150,7 +150,7 @@ static void window_news_update(rct_window *w) return; window_invalidate(w); - sound_play_panned(SOUND_CLICK_2, w->x + (w->width / 2)); + sound_play_panned(SOUND_CLICK_2, w->x + (w->width / 2), 0, 0, 0); newsItems = RCT2_ADDRESS(RCT2_ADDRESS_NEWS_ITEM_LIST, rct_news_item); j = w->news.var_480; @@ -255,7 +255,7 @@ static void window_news_scrollmousedown() w->news.var_482 = buttonIndex; w->news.var_484 = 4; window_invalidate(w); - sound_play_panned(SOUND_CLICK_1, w->x + (w->width / 2)); + sound_play_panned(SOUND_CLICK_1, w->x + (w->width / 2), 0, 0, 0); } } diff --git a/src/window_options.c b/src/windows/options.c similarity index 98% rename from src/window_options.c rename to src/windows/options.c index e1bfc20c90..9dc154ee17 100644 --- a/src/window_options.c +++ b/src/windows/options.c @@ -28,18 +28,18 @@ #include -#include "addresses.h" -#include "audio.h" -#include "config.h" -#include "gfx.h" -#include "language.h" -#include "osinterface.h" -#include "sprites.h" -#include "string_ids.h" -#include "viewport.h" -#include "widget.h" -#include "window.h" -#include "window_dropdown.h" +#include "../addresses.h" +#include "../audio/audio.h" +#include "../audio/mixer.h" +#include "../config.h" +#include "../drawing/drawing.h" +#include "../interface/viewport.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../localisation/localisation.h" +#include "../sprites.h" +#include "../platform/osinterface.h" +#include "dropdown.h" enum { WINDOW_OPTIONS_PAGE_DISPLAY, @@ -285,7 +285,7 @@ static void window_options_mouseup() window_options_set_page(w, widgetIndex - WIDX_TAB_1); break; case WIDX_HOTKEY_DROPDOWN: - RCT2_CALLPROC_EBPSAFE(0x006E3884); + window_shortcut_keys_open(); break; case WIDX_SCREEN_EDGE_SCROLLING: RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_EDGE_SCROLLING, uint8) ^= 1; @@ -503,6 +503,15 @@ static void window_options_dropdown() switch (widgetIndex) { case WIDX_SOUND_DROPDOWN: audio_init2(dropdownIndex); + if (dropdownIndex < gAudioDeviceCount) { +#ifdef USE_MIXER + int devicenum = dropdownIndex; + if (devicenum == 0) { + devicenum = 1; + } + Mixer_Init(gAudioDevices[devicenum].name); +#endif + } /*#ifdef _MSC_VER __asm movzx ax, dropdownIndex #else diff --git a/src/window_park.c b/src/windows/park.c similarity index 98% rename from src/window_park.c rename to src/windows/park.c index f32ecc823c..816bff17b7 100644 --- a/src/window_park.c +++ b/src/windows/park.c @@ -19,24 +19,24 @@ *****************************************************************************/ #include -#include "addresses.h" -#include "award.h" -#include "config.h" -#include "date.h" -#include "game.h" -#include "graph.h" -#include "park.h" -#include "peep.h" -#include "ride.h" -#include "scenario.h" -#include "string_ids.h" -#include "sprite.h" -#include "sprites.h" -#include "util.h" -#include "viewport.h" -#include "widget.h" -#include "window.h" -#include "window_dropdown.h" +#include "../addresses.h" +#include "../config.h" +#include "../game.h" +#include "../localisation/date.h" +#include "../localisation/localisation.h" +#include "../interface/graph.h" +#include "../interface/viewport.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../management/award.h" +#include "../peep/peep.h" +#include "../ride/ride.h" +#include "../scenario.h" +#include "../sprites.h" +#include "../util/util.h" +#include "../world/park.h" +#include "../world/sprite.h" +#include "dropdown.h" enum WINDOW_PARK_PAGE { WINDOW_PARK_PAGE_ENTRANCE, @@ -866,30 +866,7 @@ static void window_park_entrance_textinput() rct_window *w; char *text; - #ifdef _MSC_VER - __asm mov result, cl - #else - __asm__ ( "mov %[result], cl " : [result] "+m" (result) ); - #endif - - #ifdef _MSC_VER - __asm mov widgetIndex, dx - #else - __asm__ ( "mov %[widgetIndex], dx " : [widgetIndex] "+m" (widgetIndex) ); - #endif - - #ifdef _MSC_VER - __asm mov w, esi - #else - __asm__ ( "mov %[w], esi " : [w] "+m" (w) ); - #endif - - #ifdef _MSC_VER - __asm mov text, edi - #else - __asm__ ( "mov %[text], edi " : [text] "+m" (text) ); - #endif - + window_textinput_get_registers(w, widgetIndex, result, text); if (widgetIndex == WIDX_RENAME) { if (result) { diff --git a/src/windows/publisher_credits.c b/src/windows/publisher_credits.c new file mode 100644 index 0000000000..c942621723 --- /dev/null +++ b/src/windows/publisher_credits.c @@ -0,0 +1,212 @@ +/***************************************************************************** +* Copyright (c) 2014 Ted John +* OpenRCT2, an open source clone of Roller Coaster Tycoon 2. +* +* This file is part of OpenRCT2. +* +* OpenRCT2 is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. + +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. + +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*****************************************************************************/ + +#include +#include +#include "../addresses.h" +#include "../localisation/localisation.h" +#include "../sprites.h" +#include "../interface/widget.h" +#include "../interface/window.h" + +enum WINDOW_PUBLISHER_CREDITS_WIDGET_IDX { + WIDX_BACKGROUND, + WIDX_TITLE, + WIDX_CLOSE +}; + +rct_widget window_publisher_credits_widgets[] = { + { WWT_FRAME, 0, 0, 419, 0, 383, 0x0FFFFFFFF, STR_NONE }, // panel / background + { WWT_CAPTION, 0, 1, 418, 1, 14, STR_ROLLERCOASTER_TYCOON_2, STR_WINDOW_TITLE_TIP }, // title bar + { WWT_CLOSEBOX, 0, 407, 417, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, // close x button + { WWT_SCROLL, 0, 4, 415, 18, 379, 2, STR_NONE }, // scroll + { WIDGETS_END }, +}; + +static void window_publisher_credits_emptysub() { } +static void window_publisher_credits_mouseup(); +static void window_publisher_credits_scrollgetsize(); +static void window_publisher_credits_paint(); +static void window_publisher_credits_scrollpaint(); + +static void* window_publisher_credits_events[] = { + window_publisher_credits_emptysub, + window_publisher_credits_mouseup, + window_publisher_credits_emptysub, + window_publisher_credits_emptysub, + window_publisher_credits_emptysub, + window_publisher_credits_emptysub, + window_publisher_credits_emptysub, + window_publisher_credits_emptysub, + window_publisher_credits_emptysub, + window_publisher_credits_emptysub, + window_publisher_credits_emptysub, + window_publisher_credits_emptysub, + window_publisher_credits_emptysub, + window_publisher_credits_emptysub, + window_publisher_credits_emptysub, + window_publisher_credits_scrollgetsize, + window_publisher_credits_emptysub, + window_publisher_credits_emptysub, + window_publisher_credits_emptysub, + window_publisher_credits_emptysub, + window_publisher_credits_emptysub, + window_publisher_credits_emptysub, + window_publisher_credits_emptysub, + window_publisher_credits_emptysub, + window_publisher_credits_emptysub, + window_publisher_credits_emptysub, + window_publisher_credits_paint, + window_publisher_credits_scrollpaint +}; + +/** +* +* rct2: 0x0066D4EC +*/ +void window_publisher_credits_open() +{ + rct_window* window; + + // Check if window is already open + window = window_bring_to_front_by_id(WC_PUBLISHER_CREDITS, 0); + if (window != NULL) + return; + + window = window_create( + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) / 2 - 210, + max(28, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) / 2 - 192), + 420, + 384, + (uint32*)window_publisher_credits_events, + WC_PUBLISHER_CREDITS, + 0 + ); + + window->widgets = window_publisher_credits_widgets; + window->enabled_widgets = 1 << WIDX_CLOSE; + + window_init_scroll_widgets(window); + window->colours[0] = 7; + window->colours[1] = 7; + window->colours[2] = 7; + +} + +/** +* +* rct2: 0x0066D7A8 +*/ +static void window_publisher_credits_mouseup() +{ + short widgetIndex; + rct_window *w; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + } +} + +/** +* +* rct2: 0x0066D7B3 +*/ +static void window_publisher_credits_scrollgetsize() +{ + int y = 820; + +#ifdef _MSC_VER + __asm mov edx, y +#else + __asm__("mov edx, %[y] " : [y] "+m" (y)); +#endif +} + +/** +* +* rct2: 0x0066D5CB +*/ +static void window_publisher_credits_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); +} + +int credits_order[] = { + 0xB5D, + 0xB5E, + 0xB5F, + 0xB60, + 0xB61, + 0xB62, + 0xB63, + 0xB64, + 0xB72, + 0xB71, + 0xB65, + 0xB66, + 0xB6F, + 0xB70, + 0xB67, + 0xB68, + 0xB69, + 0xB6A, + 0xB6B, + 0xB6D, + 0xB6E, + 0xB6C, +}; + +/** +* +* rct2: 0x0066D5D1 +*/ +static void window_publisher_credits_scrollpaint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + window_paint_get_registers(w, dpi); + + int x = 200; + int y = 2; + + gfx_draw_sprite(dpi, SPR_CREDITS_INFOGRAMES, x - 49, y, 0); + + y += 86; + + draw_string_centred_underline(dpi, 0xB5C, 0, 0, x, y); + + y += 14; + + for (int i = 0; i < sizeof(credits_order)/sizeof(int); i++) { + gfx_draw_string_centred(dpi, credits_order[i], x, y, 0, 0); + y += 11; + } + + +} \ No newline at end of file diff --git a/src/window_research.c b/src/windows/research.c similarity index 94% rename from src/window_research.c rename to src/windows/research.c index 5685c80da1..bb303e8f5e 100644 --- a/src/window_research.c +++ b/src/windows/research.c @@ -18,17 +18,18 @@ * along with this program. If not, see . *****************************************************************************/ -#include "addresses.h" -#include "finance.h" -#include "game.h" -#include "news_item.h" -#include "ride.h" -#include "scenery.h" -#include "string_ids.h" -#include "sprites.h" -#include "widget.h" -#include "window.h" -#include "window_dropdown.h" +#include "../addresses.h" +#include "../game.h" +#include "../localisation/localisation.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../management/finance.h" +#include "../management/news_item.h" +#include "../management/research.h" +#include "../ride/ride.h" +#include "../sprites.h" +#include "../world/scenery.h" +#include "dropdown.h" enum { WINDOW_RESEARCH_PAGE_DEVELOPMENT, @@ -196,7 +197,8 @@ static void* window_research_page_events[] = { static uint32 window_research_page_enabled_widgets[] = { (1 << WIDX_CLOSE) | (1 << WIDX_TAB_1) | - (1 << WIDX_TAB_2), + (1 << WIDX_TAB_2) | + (1 << WIDX_LAST_DEVELOPMENT_BUTTON), (1 << WIDX_CLOSE) | (1 << WIDX_TAB_1) | @@ -236,7 +238,7 @@ void window_research_open() w->colours[0] = 1; w->colours[1] = 19; w->colours[2] = 19; - RCT2_CALLPROC_EBPSAFE(0x00684BAE); + research_update_uncompleted_types(); } w->page = 0; @@ -339,10 +341,10 @@ static void window_research_development_paint() // Research type stringId = STR_RESEARCH_UNKNOWN; - if (RCT2_GLOBAL(0x01357CF3, uint8) != 0) { - stringId = STR_TRANSPORT_RIDE + RCT2_GLOBAL(0x013580E6, uint8); - if (RCT2_GLOBAL(0x01357CF3, uint8) != 1) { - uint32 typeId = RCT2_GLOBAL(0x013580E0, uint32); + if (RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8) != 0) { + stringId = STR_TRANSPORT_RIDE + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_CATEGORY, uint8); + if (RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8) != 1) { + uint32 typeId = RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_ITEM, uint32); if (typeId >= 0x10000) { rct_ride_type *rideEntry = RCT2_GLOBAL(0x009ACFA4 + (typeId & 0xFF) * 4, rct_ride_type*); stringId = rideEntry->var_008 & 0x1000 ? @@ -357,13 +359,13 @@ static void window_research_development_paint() y += 25; // Progress - stringId = 2285 + RCT2_GLOBAL(0x01357CF3, uint8); + stringId = 2285 + RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8); gfx_draw_string_left_wrapped(dpi, &stringId, x, y, 296, STR_RESEARCH_PROGRESS_LABEL, 0); y += 15; // Expected RCT2_GLOBAL(0x013CE952, uint16) = STR_UNKNOWN; - if (RCT2_GLOBAL(0x01357CF3, uint8) != 0) { + if (RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8) != 0) { uint16 expectedDay = RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_EXPECTED_DAY, uint8); if (expectedDay != 255) { RCT2_GLOBAL(0x013CE952 + 2, uint16) = STR_DATE_DAY_1 + expectedDay; @@ -529,13 +531,13 @@ static void window_research_funding_invalidate() // Checkboxes int activeResearchTypes = RCT2_GLOBAL(RCT2_ADDRESS_ACTIVE_RESEARCH_TYPES, uint16); - int uncompletedResearchTypes = RCT2_GLOBAL(RCT2_ADDRESS_UNCOMPLETED_RESEARCH_TYPES, uint16); + int uncompletedResearchTypes = gResearchUncompletedCategories; for (int i = 0; i < 7; i++) { int mask = 1 << i; int widgetMask = 1 << (i + WIDX_TRANSPORT_RIDES); // Set checkbox disabled if research type is complete - if (uncompletedResearchTypes & mask) { + if (gResearchUncompletedCategories & mask) { w->disabled_widgets &= ~widgetMask; // Set checkbox ticked if research type is active diff --git a/src/windows/ride.c b/src/windows/ride.c new file mode 100644 index 0000000000..6cec49b004 --- /dev/null +++ b/src/windows/ride.c @@ -0,0 +1,5701 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of OpenRCT2. + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#include +#include "../addresses.h" +#include "../game.h" +#include "../interface/viewport.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../localisation/localisation.h" +#include "../peep/staff.h" +#include "../ride/ride.h" +#include "../ride/ride_data.h" +#include "../sprites.h" +#include "../world/map.h" +#include "../world/sprite.h" +#include "dropdown.h" + +#define var_496(w) RCT2_GLOBAL((int)w + 0x496, uint16) + +enum WINDOW_PARK_PAGE { + WINDOW_PARK_PAGE_MAIN, + WINDOW_PARK_PAGE_VEHICLE, + WINDOW_PARK_PAGE_OPERATING, + WINDOW_PARK_PAGE_MAINTENANCE, + WINDOW_PARK_PAGE_COLOUR, + WINDOW_PARK_PAGE_MUSIC, + WINDOW_PARK_PAGE_MEASUREMENTS, + WINDOW_PARK_PAGE_GRAPHS, + WINDOW_PARK_PAGE_INCOME, + WINDOW_PARK_PAGE_CUSTOMER, + WINDOW_PARK_PAGE_COUNT +}; + +#pragma region Widgets + +enum { + WIDX_BACKGROUND, + WIDX_TITLE, + WIDX_CLOSE, + WIDX_PAGE_BACKGROUND, + WIDX_TAB_1, + WIDX_TAB_2, + WIDX_TAB_3, + WIDX_TAB_4, + WIDX_TAB_5, + WIDX_TAB_6, + WIDX_TAB_7, + WIDX_TAB_8, + WIDX_TAB_9, + WIDX_TAB_10, + + WIDX_VIEWPORT = 14, + WIDX_VIEW, + WIDX_VIEW_DROPDOWN, + WIDX_STATUS, + WIDX_OPEN, + WIDX_CONSTRUCTION, + WIDX_RENAME, + WIDX_LOCATE, + WIDX_DEMOLISH, + + WIDX_VEHICLE_TYPE = 14, + WIDX_VEHICLE_TYPE_DROPDOWN, + WIDX_VEHICLE_TRAINS_PREVIEW, + WIDX_VEHICLE_TRAINS, + WIDX_VEHICLE_TRAINS_DROPDOWN, + WIDX_VEHICLE_CARS_PER_TRAIN, + WIDX_VEHICLE_CARS_PER_TRAIN_DROPDOWN, + + WIDX_MODE_TWEAK = 14, + WIDX_MODE_TWEAK_INCREASE, + WIDX_MODE_TWEAK_DECREASE, + WIDX_LIFT_HILL_SPEED, + WIDX_LIFT_HILL_SPEED_INCREASE, + WIDX_LIFT_HILL_SPEED_DECREASE, + WIDX_LOAD_CHECKBOX, + WIDX_LEAVE_WHEN_ANOTHER_ARRIVES_CHECKBOX, + WIDX_MINIMUM_LENGTH_CHECKBOX, + WIDX_MINIMUM_LENGTH, + WIDX_MINIMUM_LENGTH_INCREASE, + WIDX_MINIMUM_LENGTH_DECREASE, + WIDX_MAXIMUM_LENGTH_CHECKBOX, + WIDX_MAXIMUM_LENGTH, + WIDX_MAXIMUM_LENGTH_INCREASE, + WIDX_MAXIMUM_LENGTH_DECREASE, + WIDX_SYNCHRONISE_WITH_ADJACENT_STATIONS_CHECKBOX, + WIDX_MODE_TWEAK_LABEL, + WIDX_LIFT_HILL_SPEED_LABEL, + WIDX_MODE, + WIDX_MODE_DROPDOWN, + WIDX_LOAD, + WIDX_LOAD_DROPDOWN, + WIDX_OPERATE_NUMBER_OF_CIRCUITS_LABEL, + WIDX_OPERATE_NUMBER_OF_CIRCUITS, + WIDX_OPERATE_NUMBER_OF_CIRCUITS_INCREASE, + WIDX_OPERATE_NUMBER_OF_CIRCUITS_DECREASE, + + WIDX_INSPECTION_INTERVAL = 14, + WIDX_INSPECTION_INTERVAL_DROPDOWN, + WIDX_LOCATE_MECHANIC, + + WIDX_TRACK_PREVIEW = 14, + WIDX_TRACK_COLOUR_SCHEME, + WIDX_TRACK_COLOUR_SCHEME_DROPDOWN, + WIDX_TRACK_MAIN_COLOUR, + WIDX_TRACK_ADDITIONAL_COLOUR, + WIDX_TRACK_SUPPORT_COLOUR, + WIDX_MAZE_STYLE, + WIDX_MAZE_STYLE_DROPDOWN, + WIDX_PAINT_INDIVIDUAL_AREA, + WIDX_ENTRANCE_PREVIEW, + WIDX_ENTRANCE_STYLE, + WIDX_ENTRANCE_STYLE_DROPDOWN, + WIDX_VEHICLE_PREVIEW, + WIDX_VEHICLE_COLOUR_SCHEME, + WIDX_VEHICLE_COLOUR_SCHEME_DROPDOWN, + WIDX_VEHICLE_COLOUR_INDEX, + WIDX_VEHICLE_COLOUR_INDEX_DROPDOWN, + WIDX_VEHICLE_MAIN_COLOUR, + WIDX_VEHICLE_ADDITIONAL_COLOUR_1, + WIDX_VEHICLE_ADDITIONAL_COLOUR_2, + + WIDX_PLAY_MUSIC = 14, + WIDX_MUSIC, + WIDX_MUSIC_DROPDOWN, + + WIDX_SAVE_TRACK_DESIGN = 14, + WIDX_SELECT_NEARBY_SCENERY, + WIDX_RESET_SELECTION, + WIDX_SAVE_DESIGN, + WIDX_CANCEL_DESIGN, + + WIDX_GRAPH = 14, + WIDX_GRAPH_VELOCITY, + WIDX_GRAPH_ALTITUDE, + WIDX_GRAPH_VERTICAL, + WIDX_GRAPH_LATERAL, + + WIDX_PRIMARY_PRICE_LABEL = 14, + WIDX_PRIMARY_PRICE, + WIDX_PRIMARY_PRICE_INCREASE, + WIDX_PRIMARY_PRICE_DECREASE, + WIDX_PRIMARY_PRICE_SAME_THROUGHOUT_PARK, + WIDX_SECONDARY_PRICE_LABEL, + WIDX_SECONDARY_PRICE, + WIDX_SECONDARY_PRICE_INCREASE, + WIDX_SECONDARY_PRICE_DECREASE, + WIDX_SECONDARY_PRICE_SAME_THROUGHOUT_PARK, + + WIDX_SHOW_GUESTS_THOUGHTS = 14, + WIDX_SHOW_GUESTS_ON_RIDE, + WIDX_SHOW_GUESTS_QUEUING +}; + +// 0x009ADC34 +static rct_widget window_ride_main_widgets[] = { + { WWT_FRAME, 0, 0, 315, 0, 206, 0x0FFFFFFFF, STR_NONE }, + { WWT_CAPTION, 0, 1, 314, 1, 14, 0x3DD, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, 303, 313, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WWT_RESIZE, 1, 0, 315, 43, 179, 0x0FFFFFFFF, STR_NONE }, + { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_VIEW_OF_RIDE_ATTRACTION_TIP }, + { WWT_TAB, 1, 34, 64, 17, 46, 0x2000144E, STR_VEHICLE_DETAILS_AND_OPTIONS_TIP }, + { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_OPERATING_OPTIONS_TIP }, + { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, STR_MAINTENANCE_OPTIONS_TIP }, + { WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, STR_COLOUR_SCHEME_OPTIONS_TIP }, + { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, STR_SOUND_AND_MUSIC_OPTIONS_TIP }, + { WWT_TAB, 1, 189, 219, 17, 43, 0x2000144E, STR_MEASUREMENTS_AND_TEST_DATA_TIP }, + { WWT_TAB, 1, 220, 250, 17, 43, 0x2000144E, STR_GRAPHS_TIP }, + { WWT_TAB, 1, 251, 281, 17, 43, 0x2000144E, STR_INCOME_AND_COSTS_TIP }, + { WWT_TAB, 1, 282, 312, 17, 43, 0x2000144E, STR_CUSTOMER_INFORMATION_TIP }, + + { WWT_VIEWPORT, 1, 3, 290, 60, 166, 0x0FFFFFFFE, STR_NONE }, + { WWT_DROPDOWN, 1, 35, 256, 46, 57, 0x0FFFFFFFF, STR_VIEW_SELECTION }, + { WWT_DROPDOWN_BUTTON, 1, 245, 255, 47, 56, 876, STR_VIEW_SELECTION }, + { WWT_12, 1, 3, 290, 167, 177, 0x0FFFFFFFF, STR_NONE }, + { WWT_FLATBTN, 1, 291, 314, 46, 69, 0x0FFFFFFFF, STR_OPEN_CLOSE_OR_TEST_RIDE }, + { WWT_FLATBTN, 1, 291, 314, 70, 93, SPR_CONSTRUCTION, STR_CONSTRUCTION }, + { WWT_FLATBTN, 1, 291, 314, 94, 117, SPR_RENAME, STR_NAME_RIDE_TIP }, + { WWT_FLATBTN, 1, 291, 314, 118, 141, SPR_LOCATE, STR_LOCATE_SUBJECT_TIP }, + { WWT_FLATBTN, 1, 291, 314, 142, 165, SPR_DEMOLISH, STR_DEMOLISH_RIDE_TIP }, + { WIDGETS_END }, +}; + +// 0x009ADDA8 +static rct_widget window_ride_vehicle_widgets[] = { + { WWT_FRAME, 0, 0, 315, 0, 206, 0x0FFFFFFFF, STR_NONE }, + { WWT_CAPTION, 0, 1, 314, 1, 14, 0x3DD, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, 303, 313, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WWT_RESIZE, 1, 0, 315, 43, 179, 0x0FFFFFFFF, STR_NONE }, + { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_VIEW_OF_RIDE_ATTRACTION_TIP }, + { WWT_TAB, 1, 34, 64, 17, 46, 0x2000144E, STR_VEHICLE_DETAILS_AND_OPTIONS_TIP }, + { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_OPERATING_OPTIONS_TIP }, + { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, STR_MAINTENANCE_OPTIONS_TIP }, + { WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, STR_COLOUR_SCHEME_OPTIONS_TIP }, + { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, STR_SOUND_AND_MUSIC_OPTIONS_TIP }, + { WWT_TAB, 1, 189, 219, 17, 43, 0x2000144E, STR_MEASUREMENTS_AND_TEST_DATA_TIP }, + { WWT_TAB, 1, 220, 250, 17, 43, 0x2000144E, STR_GRAPHS_TIP }, + { WWT_TAB, 1, 251, 281, 17, 43, 0x2000144E, STR_INCOME_AND_COSTS_TIP }, + { WWT_TAB, 1, 282, 312, 17, 43, 0x2000144E, STR_CUSTOMER_INFORMATION_TIP }, + + { WWT_DROPDOWN, 1, 7, 308, 50, 61, 0xFFFFFFFF, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 297, 307, 51, 60, 876, STR_NONE }, + { WWT_SCROLL, 1, 7, 308, 141, 183, 0, STR_NONE }, + { WWT_DROPDOWN, 1, 7, 151, 190, 201, 1021, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 140, 150, 191, 200, 876, STR_NONE }, + { WWT_DROPDOWN, 1, 164, 308, 190, 201, 1022, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 297, 307, 191, 200, 876, STR_NONE }, + { WIDGETS_END }, +}; + +// 0x009ADEFC +static rct_widget window_ride_operating_widgets[] = { + { WWT_FRAME, 0, 0, 315, 0, 206, 0x0FFFFFFFF, STR_NONE }, + { WWT_CAPTION, 0, 1, 314, 1, 14, 0x3DD, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, 303, 313, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WWT_RESIZE, 1, 0, 315, 43, 179, 0x0FFFFFFFF, STR_NONE }, + { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_VIEW_OF_RIDE_ATTRACTION_TIP }, + { WWT_TAB, 1, 34, 64, 17, 46, 0x2000144E, STR_VEHICLE_DETAILS_AND_OPTIONS_TIP }, + { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_OPERATING_OPTIONS_TIP }, + { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, STR_MAINTENANCE_OPTIONS_TIP }, + { WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, STR_COLOUR_SCHEME_OPTIONS_TIP }, + { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, STR_SOUND_AND_MUSIC_OPTIONS_TIP }, + { WWT_TAB, 1, 189, 219, 17, 43, 0x2000144E, STR_MEASUREMENTS_AND_TEST_DATA_TIP }, + { WWT_TAB, 1, 220, 250, 17, 43, 0x2000144E, STR_GRAPHS_TIP }, + { WWT_TAB, 1, 251, 281, 17, 43, 0x2000144E, STR_INCOME_AND_COSTS_TIP }, + { WWT_TAB, 1, 282, 312, 17, 43, 0x2000144E, STR_CUSTOMER_INFORMATION_TIP }, + + { WWT_SPINNER, 1, 157, 308, 61, 72, 874, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 297, 307, 62, 66, STR_NUMERIC_UP, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 297, 307, 67, 71, STR_NUMERIC_DOWN, STR_NONE }, + { WWT_SPINNER, 1, 157, 308, 75, 86, 3096, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 297, 307, 76, 80, STR_NUMERIC_UP, STR_SELECT_LIFT_HILL_CHAIN_SPEED_TIP }, + { WWT_DROPDOWN_BUTTON, 1, 297, 307, 81, 85, STR_NUMERIC_DOWN, STR_SELECT_LIFT_HILL_CHAIN_SPEED_TIP }, + { WWT_CHECKBOX, 1, 7, 86, 109, 120, STR_WAIT_FOR, STR_WAIT_FOR_PASSENGERS_BEFORE_DEPARTING_TIP }, + { WWT_CHECKBOX, 1, 7, 308, 124, 135, 0xFFFFFFFF, STR_NONE }, + { WWT_CHECKBOX, 1, 7, 156, 139, 150, STR_MINIMUM_WAITING_TIME, STR_MINIMUM_LENGTH_BEFORE_DEPARTING_TIP }, + { WWT_SPINNER, 1, 157, 308, 139, 150, 870, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 297, 307, 140, 144, STR_NUMERIC_UP, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 297, 307, 145, 149, STR_NUMERIC_DOWN, STR_NONE }, + { WWT_CHECKBOX, 1, 7, 156, 154, 165, STR_MAXIMUM_WAITING_TIME, STR_MAXIMUM_LENGTH_BEFORE_DEPARTING_TIP }, + { WWT_SPINNER, 1, 157, 308, 154, 165, 872, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 297, 307, 155, 159, STR_NUMERIC_UP, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 297, 307, 160, 164, STR_NUMERIC_DOWN, STR_NONE }, + { WWT_CHECKBOX, 1, 7, 308, 169, 180, STR_SYNCHRONISE_WITH_ADJACENT_STATIONS, STR_SYNCHRONISE_WITH_ADJACENT_STATIONS_TIP }, + { WWT_24, 1, 7, 149, 61, 72, 0xFFFFFFFF, STR_NONE }, + { WWT_24, 1, 7, 149, 75, 86, 3095, STR_NONE }, + { WWT_DROPDOWN, 1, 7, 308, 47, 58, 0xFFFFFFFF, STR_SELECT_OPERATING_MODE }, + { WWT_DROPDOWN_BUTTON, 1, 297, 307, 48, 57, 876, STR_SELECT_OPERATING_MODE }, + { WWT_DROPDOWN, 1, 87, 308, 109, 120, 0xFFFFFFFF, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 297, 307, 110, 119, 876, STR_NONE }, + { WWT_24, 1, 7, 149, 89, 100, STR_NUMBER_OF_CIRCUITS, STR_NUMBER_OF_CIRCUITS_TIP }, + { WWT_SPINNER, 1, 157, 308, 89, 100, 1957, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 297, 307, 90, 94, STR_NUMERIC_UP, STR_SELECT_LIFT_HILL_CHAIN_SPEED_TIP }, + { WWT_DROPDOWN_BUTTON, 1, 297, 307, 95, 99, STR_NUMERIC_DOWN, STR_SELECT_LIFT_HILL_CHAIN_SPEED_TIP }, + { WIDGETS_END }, +}; + +// 0x009AE190 +static rct_widget window_ride_maintenance_widgets[] = { + { WWT_FRAME, 0, 0, 315, 0, 206, 0x0FFFFFFFF, STR_NONE }, + { WWT_CAPTION, 0, 1, 314, 1, 14, 0x3DD, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, 303, 313, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WWT_RESIZE, 1, 0, 315, 43, 179, 0x0FFFFFFFF, STR_NONE }, + { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_VIEW_OF_RIDE_ATTRACTION_TIP }, + { WWT_TAB, 1, 34, 64, 17, 46, 0x2000144E, STR_VEHICLE_DETAILS_AND_OPTIONS_TIP }, + { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_OPERATING_OPTIONS_TIP }, + { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, STR_MAINTENANCE_OPTIONS_TIP }, + { WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, STR_COLOUR_SCHEME_OPTIONS_TIP }, + { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, STR_SOUND_AND_MUSIC_OPTIONS_TIP }, + { WWT_TAB, 1, 189, 219, 17, 43, 0x2000144E, STR_MEASUREMENTS_AND_TEST_DATA_TIP }, + { WWT_TAB, 1, 220, 250, 17, 43, 0x2000144E, STR_GRAPHS_TIP }, + { WWT_TAB, 1, 251, 281, 17, 43, 0x2000144E, STR_INCOME_AND_COSTS_TIP }, + { WWT_TAB, 1, 282, 312, 17, 43, 0x2000144E, STR_CUSTOMER_INFORMATION_TIP }, + + { WWT_DROPDOWN, 1, 107, 308, 71, 82, 0, STR_SELECT_HOW_OFTEN_A_MECHANIC_SHOULD_CHECK_THIS_RIDE }, + { WWT_DROPDOWN_BUTTON, 1, 297, 307, 72, 81, 876, STR_SELECT_HOW_OFTEN_A_MECHANIC_SHOULD_CHECK_THIS_RIDE }, + { WWT_FLATBTN, 1, 289, 312, 108, 131, 0xFFFFFFFF, STR_LOCATE_NEAREST_AVAILABLE_MECHANIC_TIP }, + { WIDGETS_END }, +}; + +// 0x009AE2A4 +static rct_widget window_ride_colour_widgets[] = { + { WWT_FRAME, 0, 0, 315, 0, 206, 0x0FFFFFFFF, STR_NONE }, + { WWT_CAPTION, 0, 1, 314, 1, 14, 0x3DD, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, 303, 313, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WWT_RESIZE, 1, 0, 315, 43, 179, 0x0FFFFFFFF, STR_NONE }, + { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_VIEW_OF_RIDE_ATTRACTION_TIP }, + { WWT_TAB, 1, 34, 64, 17, 46, 0x2000144E, STR_VEHICLE_DETAILS_AND_OPTIONS_TIP }, + { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_OPERATING_OPTIONS_TIP }, + { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, STR_MAINTENANCE_OPTIONS_TIP }, + { WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, STR_COLOUR_SCHEME_OPTIONS_TIP }, + { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, STR_SOUND_AND_MUSIC_OPTIONS_TIP }, + { WWT_TAB, 1, 189, 219, 17, 43, 0x2000144E, STR_MEASUREMENTS_AND_TEST_DATA_TIP }, + { WWT_TAB, 1, 220, 250, 17, 43, 0x2000144E, STR_GRAPHS_TIP }, + { WWT_TAB, 1, 251, 281, 17, 43, 0x2000144E, STR_INCOME_AND_COSTS_TIP }, + { WWT_TAB, 1, 282, 312, 17, 43, 0x2000144E, STR_CUSTOMER_INFORMATION_TIP }, + + { WWT_SPINNER, 1, 3, 70, 47, 93, 0xFFFFFFFF, STR_NONE }, + { WWT_DROPDOWN, 1, 74, 312, 49, 60, 872, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 301, 311, 50, 59, 876, STR_COLOUR_SCHEME_TO_CHANGE_TIP }, + { WWT_COLORBTN, 1, 79, 90, 74, 85, 0xFFFFFFFF, STR_SELECT_MAIN_COLOUR_TIP }, + { WWT_COLORBTN, 1, 99, 110, 74, 85, 0xFFFFFFFF, STR_SELECT_ADDITIONAL_COLOUR_1_TIP }, + { WWT_COLORBTN, 1, 119, 130, 74, 85, 0xFFFFFFFF, STR_SELECT_SUPPORT_STRUCTURE_COLOUR_TIP }, + { WWT_DROPDOWN, 1, 74, 312, 49, 60, 0xFFFFFFFF, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 301, 311, 50, 59, 876, STR_NONE }, + { WWT_FLATBTN, 1, 289, 312, 68, 91, 5173, STR_PAINT_INDIVIDUAL_AREA_TIP }, + { WWT_SPINNER, 1, 245, 312, 101, 147, 0xFFFFFFFF, STR_NONE }, + { WWT_DROPDOWN, 1, 3, 241, 103, 114, 0, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 230, 240, 104, 113, 876, STR_SELECT_STYLE_OF_ENTRANCE_EXIT_STATION_TIP }, + { WWT_SCROLL, 1, 3, 70, 157, 203, 0, STR_NONE }, + { WWT_DROPDOWN, 1, 74, 312, 157, 168, 868, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 301, 311, 158, 167, 876, STR_SELECT_VEHICLE_COLOUR_SCHEME_TIP }, + { WWT_DROPDOWN, 1, 74, 312, 173, 184, 0xFFFFFFFF, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 301, 311, 174, 183, 876, STR_SELECT_VEHICLE_TO_MODIFY_TIP }, + { WWT_COLORBTN, 1, 79, 90, 190, 201, 0xFFFFFFFF, STR_SELECT_MAIN_COLOUR_TIP }, + { WWT_COLORBTN, 1, 99, 110, 190, 201, 0xFFFFFFFF, STR_SELECT_ADDITIONAL_COLOUR_1_TIP }, + { WWT_COLORBTN, 1, 119, 130, 190, 201, 0xFFFFFFFF, STR_SELECT_ADDITIONAL_COLOUR_2_TIP }, + { WIDGETS_END }, +}; + +// 0x009AE4C8 +static rct_widget window_ride_music_widgets[] = { + { WWT_FRAME, 0, 0, 315, 0, 206, 0x0FFFFFFFF, STR_NONE }, + { WWT_CAPTION, 0, 1, 314, 1, 14, 0x3DD, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, 303, 313, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WWT_RESIZE, 1, 0, 315, 43, 179, 0x0FFFFFFFF, STR_NONE }, + { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_VIEW_OF_RIDE_ATTRACTION_TIP }, + { WWT_TAB, 1, 34, 64, 17, 46, 0x2000144E, STR_VEHICLE_DETAILS_AND_OPTIONS_TIP }, + { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_OPERATING_OPTIONS_TIP }, + { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, STR_MAINTENANCE_OPTIONS_TIP }, + { WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, STR_COLOUR_SCHEME_OPTIONS_TIP }, + { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, STR_SOUND_AND_MUSIC_OPTIONS_TIP }, + { WWT_TAB, 1, 189, 219, 17, 43, 0x2000144E, STR_MEASUREMENTS_AND_TEST_DATA_TIP }, + { WWT_TAB, 1, 220, 250, 17, 43, 0x2000144E, STR_GRAPHS_TIP }, + { WWT_TAB, 1, 251, 281, 17, 43, 0x2000144E, STR_INCOME_AND_COSTS_TIP }, + { WWT_TAB, 1, 282, 312, 17, 43, 0x2000144E, STR_CUSTOMER_INFORMATION_TIP }, + + { WWT_CHECKBOX, 1, 7, 308, 47, 58, STR_PLAY_MUSIC, STR_SELECT_MUSIC_TIP }, + { WWT_DROPDOWN, 1, 7, 308, 62, 73, 0, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 297, 307, 63, 72, 876, STR_SELECT_MUSIC_STYLE_TIP }, + { WIDGETS_END }, +}; + +// 0x009AE5DC +static rct_widget window_ride_measurements_widgets[] = { + { WWT_FRAME, 0, 0, 315, 0, 206, 0x0FFFFFFFF, STR_NONE }, + { WWT_CAPTION, 0, 1, 314, 1, 14, 0x3DD, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, 303, 313, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WWT_RESIZE, 1, 0, 315, 43, 179, 0x0FFFFFFFF, STR_NONE }, + { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_VIEW_OF_RIDE_ATTRACTION_TIP }, + { WWT_TAB, 1, 34, 64, 17, 46, 0x2000144E, STR_VEHICLE_DETAILS_AND_OPTIONS_TIP }, + { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_OPERATING_OPTIONS_TIP }, + { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, STR_MAINTENANCE_OPTIONS_TIP }, + { WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, STR_COLOUR_SCHEME_OPTIONS_TIP }, + { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, STR_SOUND_AND_MUSIC_OPTIONS_TIP }, + { WWT_TAB, 1, 189, 219, 17, 43, 0x2000144E, STR_MEASUREMENTS_AND_TEST_DATA_TIP }, + { WWT_TAB, 1, 220, 250, 17, 43, 0x2000144E, STR_GRAPHS_TIP }, + { WWT_TAB, 1, 251, 281, 17, 43, 0x2000144E, STR_INCOME_AND_COSTS_TIP }, + { WWT_TAB, 1, 282, 312, 17, 43, 0x2000144E, STR_CUSTOMER_INFORMATION_TIP }, + + { WWT_FLATBTN, 1, 288, 311, 164, 187, 5183, STR_SAVE_TRACK_DESIGN }, + { WWT_DROPDOWN_BUTTON, 1, 4, 157, 128, 139, STR_SELECT_NEARBY_SCENERY, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 158, 311, 128, 139, STR_RESET_SELECTION, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 4, 157, 178, 189, STR_DESIGN_SAVE, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 158, 311, 178, 189, STR_DESIGN_CANCEL, STR_NONE }, + { WIDGETS_END }, +}; + +// 0x009AE710 +static rct_widget window_ride_graphs_widgets[] = { + { WWT_FRAME, 0, 0, 315, 0, 206, 0x0FFFFFFFF, STR_NONE }, + { WWT_CAPTION, 0, 1, 314, 1, 14, 0x3DD, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, 303, 313, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WWT_RESIZE, 1, 0, 315, 43, 179, 0x0FFFFFFFF, STR_NONE }, + { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_VIEW_OF_RIDE_ATTRACTION_TIP }, + { WWT_TAB, 1, 34, 64, 17, 46, 0x2000144E, STR_VEHICLE_DETAILS_AND_OPTIONS_TIP }, + { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_OPERATING_OPTIONS_TIP }, + { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, STR_MAINTENANCE_OPTIONS_TIP }, + { WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, STR_COLOUR_SCHEME_OPTIONS_TIP }, + { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, STR_SOUND_AND_MUSIC_OPTIONS_TIP }, + { WWT_TAB, 1, 189, 219, 17, 43, 0x2000144E, STR_MEASUREMENTS_AND_TEST_DATA_TIP }, + { WWT_TAB, 1, 220, 250, 17, 43, 0x2000144E, STR_GRAPHS_TIP }, + { WWT_TAB, 1, 251, 281, 17, 43, 0x2000144E, STR_INCOME_AND_COSTS_TIP }, + { WWT_TAB, 1, 282, 312, 17, 43, 0x2000144E, STR_CUSTOMER_INFORMATION_TIP }, + + { WWT_SCROLL, 1, 3, 308, 46, 157, 1, STR_LOGGING_DATA_FROM_TIP }, + { WWT_DROPDOWN_BUTTON, 1, 3, 75, 163, 176, 1415, STR_SHOW_GRAPH_OF_VELOCITY_AGAINST_TIME_TIP }, + { WWT_DROPDOWN_BUTTON, 1, 76, 148, 163, 176, 1416, STR_SHOW_GRAPH_OF_ALTITUDE_AGAINST_TIME_TIP }, + { WWT_DROPDOWN_BUTTON, 1, 149, 221, 163, 176, 1417, STR_SHOW_GRAPH_OF_VERTICAL_ACCELERATION_AGAINST_TIME_TIP }, + { WWT_DROPDOWN_BUTTON, 1, 222, 294, 163, 176, 1418, STR_SHOW_GRAPH_OF_LATERAL_ACCELERATION_AGAINST_TIME_TIP }, + { WIDGETS_END }, +}; + +// 0x009AE844 +static rct_widget window_ride_income_widgets[] = { + { WWT_FRAME, 0, 0, 315, 0, 206, 0x0FFFFFFFF, STR_NONE }, + { WWT_CAPTION, 0, 1, 314, 1, 14, 0x3DD, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, 303, 313, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WWT_RESIZE, 1, 0, 315, 43, 179, 0x0FFFFFFFF, STR_NONE }, + { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_VIEW_OF_RIDE_ATTRACTION_TIP }, + { WWT_TAB, 1, 34, 64, 17, 46, 0x2000144E, STR_VEHICLE_DETAILS_AND_OPTIONS_TIP }, + { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_OPERATING_OPTIONS_TIP }, + { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, STR_MAINTENANCE_OPTIONS_TIP }, + { WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, STR_COLOUR_SCHEME_OPTIONS_TIP }, + { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, STR_SOUND_AND_MUSIC_OPTIONS_TIP }, + { WWT_TAB, 1, 189, 219, 17, 43, 0x2000144E, STR_MEASUREMENTS_AND_TEST_DATA_TIP }, + { WWT_TAB, 1, 220, 250, 17, 43, 0x2000144E, STR_GRAPHS_TIP }, + { WWT_TAB, 1, 251, 281, 17, 43, 0x2000144E, STR_INCOME_AND_COSTS_TIP }, + { WWT_TAB, 1, 282, 312, 17, 43, 0x2000144E, STR_CUSTOMER_INFORMATION_TIP }, + + { WWT_24, 1, 5, 144, 50, 61, 0xFFFFFFFF, STR_NONE }, + { WWT_SPINNER, 1, 147, 308, 50, 61, 1429, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 297, 307, 51, 55, STR_NUMERIC_UP, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 297, 307, 56, 60, STR_NUMERIC_DOWN, STR_NONE }, + { WWT_CHECKBOX, 1, 5, 310, 61, 72, STR_SAME_PRICE_THROUGHOUT_PARK, STR_SAME_PRICE_THROUGHOUT_PARK_TIP }, + { WWT_24, 1, 5, 144, 89, 100, 0xFFFFFFFF, STR_NONE }, + { WWT_SPINNER, 1, 147, 308, 89, 100, 1799, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 297, 307, 90, 94, STR_NUMERIC_UP, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 297, 307, 95, 99, STR_NUMERIC_DOWN, STR_NONE }, + { WWT_CHECKBOX, 1, 5, 310, 100, 111, STR_SAME_PRICE_THROUGHOUT_PARK, STR_SAME_PRICE_THROUGHOUT_PARK_TIP }, + { WIDGETS_END }, +}; + +// 0x009AE9C8 +static rct_widget window_ride_customer_widgets[] = { + { WWT_FRAME, 0, 0, 315, 0, 206, 0x0FFFFFFFF, STR_NONE }, + { WWT_CAPTION, 0, 1, 314, 1, 14, 0x3DD, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, 303, 313, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WWT_RESIZE, 1, 0, 315, 43, 179, 0x0FFFFFFFF, STR_NONE }, + { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_VIEW_OF_RIDE_ATTRACTION_TIP }, + { WWT_TAB, 1, 34, 64, 17, 46, 0x2000144E, STR_VEHICLE_DETAILS_AND_OPTIONS_TIP }, + { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_OPERATING_OPTIONS_TIP }, + { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, STR_MAINTENANCE_OPTIONS_TIP }, + { WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, STR_COLOUR_SCHEME_OPTIONS_TIP }, + { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, STR_SOUND_AND_MUSIC_OPTIONS_TIP }, + { WWT_TAB, 1, 189, 219, 17, 43, 0x2000144E, STR_MEASUREMENTS_AND_TEST_DATA_TIP }, + { WWT_TAB, 1, 220, 250, 17, 43, 0x2000144E, STR_GRAPHS_TIP }, + { WWT_TAB, 1, 251, 281, 17, 43, 0x2000144E, STR_INCOME_AND_COSTS_TIP }, + { WWT_TAB, 1, 282, 312, 17, 43, 0x2000144E, STR_CUSTOMER_INFORMATION_TIP }, + + { WWT_FLATBTN, 1, 289, 312, 54, 77, 5184, STR_SHOW_GUESTS_THOUGHTS_ABOUT_THIS_RIDE_ATTRACTION_TIP }, + { WWT_FLATBTN, 1, 289, 312, 78, 101, 5186, STR_SHOW_GUESTS_ON_THIS_RIDE_ATTRACTION_TIP }, + { WWT_FLATBTN, 1, 289, 312, 102, 125, 5185, STR_SHOW_GUESTS_QUEUING_FOR_THIS_RIDE_ATTRACTION_TIP }, + { WIDGETS_END }, +}; + +static rct_widget *window_ride_page_widgets[] = { + window_ride_main_widgets, + window_ride_vehicle_widgets, + window_ride_operating_widgets, + window_ride_maintenance_widgets, + window_ride_colour_widgets, + window_ride_music_widgets, + window_ride_measurements_widgets, + window_ride_graphs_widgets, + window_ride_income_widgets, + window_ride_customer_widgets +}; + +const uint64 window_ride_page_enabled_widgets[] = { + 0x00000000007DBFF4, + 0x00000000001EFFF4, + 0x0000019E777DBFF4, + 0x000000000001FFF4, + 0x00000003F37F3FF4, + 0x000000000001FFF4, + 0x000000000007FFF4, + 0x000000000007BFF4, + 0x0000000000E73FF4, + 0x000000000001FFF4 +}; + +#pragma endregion + +#pragma region Events + +static void window_ride_emptysub() { } +static void window_ride_init_viewport(rct_window *w); + +static void window_ride_main_mouseup(); +static void window_ride_main_resize(); +static void window_ride_main_mousedown(int widgetIndex, rct_window *w, rct_widget *widget); +static void window_ride_main_dropdown(); +static void window_ride_main_update(rct_window *w); +static void window_ride_main_textinput(); +static void window_ride_main_unknown_14(); +static void window_ride_main_invalidate(); +static void window_ride_main_paint(); + +static void window_ride_vehicle_mouseup(); +static void window_ride_vehicle_resize(); +static void window_ride_vehicle_mousedown(int widgetIndex, rct_window *w, rct_widget *widget); +static void window_ride_vehicle_dropdown(); +static void window_ride_vehicle_update(rct_window *w); +static void window_ride_vehicle_invalidate(); +static void window_ride_vehicle_paint(); +static void window_ride_vehicle_scrollpaint(); + +static void window_ride_operating_mouseup(); +static void window_ride_operating_resize(); +static void window_ride_operating_mousedown(int widgetIndex, rct_window *w, rct_widget *widget); +static void window_ride_operating_dropdown(); +static void window_ride_operating_update(rct_window *w); +static void window_ride_operating_invalidate(); +static void window_ride_operating_paint(); + +static void window_ride_maintenance_mouseup(); +static void window_ride_maintenance_resize(); +static void window_ride_maintenance_mousedown(int widgetIndex, rct_window *w, rct_widget *widget); +static void window_ride_maintenance_dropdown(); +static void window_ride_maintenance_update(rct_window *w); +static void window_ride_maintenance_invalidate(); +static void window_ride_maintenance_paint(); + +static void window_ride_colour_close(); +static void window_ride_colour_mouseup(); +static void window_ride_colour_resize(); +static void window_ride_colour_mousedown(int widgetIndex, rct_window *w, rct_widget *widget); +static void window_ride_colour_dropdown(); +static void window_ride_colour_update(rct_window *w); +static void window_ride_colour_tooldown(); +static void window_ride_colour_tooldrag(); +static void window_ride_colour_invalidate(); +static void window_ride_colour_paint(); +static void window_ride_colour_scrollpaint(); + +static void window_ride_music_mouseup(); +static void window_ride_music_resize(); +static void window_ride_music_mousedown(int widgetIndex, rct_window *w, rct_widget *widget); +static void window_ride_music_dropdown(); +static void window_ride_music_update(rct_window *w); +static void window_ride_music_invalidate(); +static void window_ride_music_paint(); + +static void window_ride_measurements_close(); +static void window_ride_measurements_mouseup(); +static void window_ride_measurements_resize(); +static void window_ride_measurements_mousedown(int widgetIndex, rct_window *w, rct_widget *widget); +static void window_ride_measurements_dropdown(); +static void window_ride_measurements_update(rct_window *w); +static void window_ride_measurements_tooldown(); +static void window_ride_measurements_toolabort(); +static void window_ride_measurements_invalidate(); +static void window_ride_measurements_paint(); + +static void window_ride_graphs_mouseup(); +static void window_ride_graphs_resize(); +static void window_ride_graphs_mousedown(int widgetIndex, rct_window *w, rct_widget *widget); +static void window_ride_graphs_update(rct_window *w); +static void window_ride_graphs_scrollgetheight(); +static void window_ride_graphs_15(); +static void window_ride_graphs_tooltip(); +static void window_ride_graphs_invalidate(); +static void window_ride_graphs_paint(); +static void window_ride_graphs_scrollpaint(); + +static void window_ride_income_mouseup(); +static void window_ride_income_resize(); +static void window_ride_income_mousedown(int widgetIndex, rct_window *w, rct_widget *widget); +static void window_ride_income_update(rct_window *w); +static void window_ride_income_invalidate(); +static void window_ride_income_paint(); + +static void window_ride_customer_mouseup(); +static void window_ride_customer_resize(); +static void window_ride_customer_update(rct_window *w); +static void window_ride_customer_invalidate(); +static void window_ride_customer_paint(); + +// 0x0098DFD4 +static void* window_ride_main_events[] = { + window_ride_emptysub, + window_ride_main_mouseup, + window_ride_main_resize, + window_ride_main_mousedown, + window_ride_main_dropdown, + window_ride_emptysub, + window_ride_main_update, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_main_textinput, + window_ride_main_unknown_14, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_main_invalidate, + window_ride_main_paint, + window_ride_emptysub +}; + +// 0x0098E204 +static void* window_ride_vehicle_events[] = { + window_ride_emptysub, + window_ride_vehicle_mouseup, + window_ride_vehicle_resize, + window_ride_vehicle_mousedown, + window_ride_vehicle_dropdown, + window_ride_emptysub, + window_ride_vehicle_update, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_vehicle_invalidate, + window_ride_vehicle_paint, + window_ride_vehicle_scrollpaint +}; + +// 0x0098E0B4 +static void* window_ride_operating_events[] = { + window_ride_emptysub, + window_ride_operating_mouseup, + window_ride_operating_resize, + window_ride_operating_mousedown, + window_ride_operating_dropdown, + window_ride_emptysub, + window_ride_operating_update, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_operating_invalidate, + window_ride_operating_paint, + window_ride_emptysub +}; + +// 0x0098E124 +static void* window_ride_maintenance_events[] = { + window_ride_emptysub, + window_ride_maintenance_mouseup, + window_ride_maintenance_resize, + window_ride_maintenance_mousedown, + window_ride_maintenance_dropdown, + window_ride_emptysub, + window_ride_maintenance_update, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_maintenance_invalidate, + window_ride_maintenance_paint, + window_ride_emptysub +}; + +// 0x0098E044 +static void* window_ride_colour_events[] = { + window_ride_colour_close, + window_ride_colour_mouseup, + window_ride_colour_resize, + window_ride_colour_mousedown, + window_ride_colour_dropdown, + window_ride_emptysub, + window_ride_colour_update, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_colour_tooldown, + window_ride_colour_tooldrag, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_colour_invalidate, + window_ride_colour_paint, + window_ride_colour_scrollpaint +}; + +// 0x0098E194 +static void* window_ride_music_events[] = { + window_ride_emptysub, + window_ride_music_mouseup, + window_ride_music_resize, + window_ride_music_mousedown, + window_ride_music_dropdown, + window_ride_emptysub, + window_ride_music_update, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_music_invalidate, + window_ride_music_paint, + window_ride_emptysub +}; + +// 0x0098DE14 +static void* window_ride_measurements_events[] = { + window_ride_emptysub, + window_ride_measurements_mouseup, + window_ride_measurements_resize, + window_ride_measurements_mousedown, + window_ride_measurements_dropdown, + window_ride_emptysub, + window_ride_measurements_update, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_measurements_tooldown, + window_ride_emptysub, + window_ride_emptysub, + window_ride_measurements_toolabort, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_measurements_invalidate, + window_ride_measurements_paint, + window_ride_emptysub +}; + +// 0x0098DF64 +static void* window_ride_graphs_events[] = { + window_ride_emptysub, + window_ride_graphs_mouseup, + window_ride_graphs_resize, + window_ride_graphs_mousedown, + window_ride_emptysub, + window_ride_emptysub, + window_ride_graphs_update, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_graphs_scrollgetheight, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_graphs_15, + window_ride_graphs_tooltip, + window_ride_emptysub, + window_ride_emptysub, + window_ride_graphs_invalidate, + window_ride_graphs_paint, + window_ride_graphs_scrollpaint +}; + +// 0x0098DEF4 +static void* window_ride_income_events[] = { + window_ride_emptysub, + window_ride_income_mouseup, + window_ride_income_resize, + window_ride_income_mousedown, + window_ride_emptysub, + window_ride_emptysub, + window_ride_income_update, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_income_invalidate, + window_ride_income_paint, + window_ride_emptysub +}; + +// 0x0098DE84 +static void* window_ride_customer_events[] = { + window_ride_emptysub, + window_ride_customer_mouseup, + window_ride_customer_resize, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_customer_update, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_customer_invalidate, + window_ride_customer_paint, + window_ride_emptysub +}; + +static uint32* window_ride_page_events[] = { + (uint32*)window_ride_main_events, + (uint32*)window_ride_vehicle_events, + (uint32*)window_ride_operating_events, + (uint32*)window_ride_maintenance_events, + (uint32*)window_ride_colour_events, + (uint32*)window_ride_music_events, + (uint32*)window_ride_measurements_events, + (uint32*)window_ride_graphs_events, + (uint32*)window_ride_income_events, + (uint32*)window_ride_customer_events +}; + +#pragma endregion + +const int window_ride_tab_animation_divisor[] = { 0, 0, 2, 2, 4, 2, 8, 8, 2, 0 }; +const int window_ride_tab_animation_frames[] = { 0, 0, 4, 16, 8, 16, 8, 8, 8, 0 }; + +// WINDOW_PARK_PAGE_MAIN, +// WINDOW_PARK_PAGE_VEHICLE, +// WINDOW_PARK_PAGE_OPERATING, +// WINDOW_PARK_PAGE_MAINTENANCE, +// WINDOW_PARK_PAGE_COLOUR, +// WINDOW_PARK_PAGE_MUSIC, +// WINDOW_PARK_PAGE_MEASUREMENTS, +// WINDOW_PARK_PAGE_GRAPHS, +// WINDOW_PARK_PAGE_INCOME, +// WINDOW_PARK_PAGE_CUSTOMER + +static void window_ride_draw_tab_image(rct_drawpixelinfo *dpi, rct_window *w, int page, int spriteIndex) +{ + int widgetIndex = WIDX_TAB_1 + page; + + if (!(w->disabled_widgets & (1LL << widgetIndex))) { + if (w->page == page) { + int frame = w->frame_no / window_ride_tab_animation_divisor[w->page]; + spriteIndex += (frame % window_ride_tab_animation_frames[w->page]); + } + + gfx_draw_sprite(dpi, spriteIndex, w->x + w->widgets[widgetIndex].left, w->y + w->widgets[widgetIndex].top, 0); + } +} + +/** + * + * rct2: 0x006B2E88 + */ +static void window_ride_draw_tab_main(rct_drawpixelinfo *dpi, rct_window *w) +{ + int widgetIndex = WIDX_TAB_1 + WINDOW_PARK_PAGE_MAIN; + + if (!(w->disabled_widgets & (1LL << widgetIndex))) { + int spriteIndex; + int rideType = GET_RIDE(w->number)->type; + + switch (gRideClassifications[rideType]) { + case RIDE_CLASS_RIDE: + spriteIndex = 5442; + if (w->page == WINDOW_PARK_PAGE_MAIN) + spriteIndex += (w->frame_no / 4) % 16; + break; + case RIDE_CLASS_SHOP_OR_STALL: + spriteIndex = 5351; + if (w->page == WINDOW_PARK_PAGE_MAIN) + spriteIndex += (w->frame_no / 4) % 16; + break; + case RIDE_CLASS_KIOSK_OR_FACILITY: + spriteIndex = 5367; + if (w->page == WINDOW_PARK_PAGE_MAIN) + spriteIndex += (w->frame_no / 4) % 8; + break; + } + + gfx_draw_sprite(dpi, spriteIndex, w->x + w->widgets[widgetIndex].left, w->y + w->widgets[widgetIndex].top, 0); + } +} + +/** + * + * rct2: 0x006B2B68 + */ +static void window_ride_draw_tab_vehicle(rct_drawpixelinfo *dpi, rct_window *w) +{ + rct_ride *ride; + rct_widget *widget; + int widgetIndex, spriteIndex, x, y, width, height; + uint8 *ebp; + rct_ride_type *rideEntry; + vehicle_colour vehicleColour; + + widgetIndex = WIDX_TAB_1 + WINDOW_PARK_PAGE_VEHICLE; + widget = &w->widgets[widgetIndex]; + + if (!(w->disabled_widgets & (1LL << widgetIndex))) { + x = widget->left + 1; + y = widget->top + 1; + width = widget->right - x; + height = widget->bottom - 3 - y; + if (w->page == WINDOW_PARK_PAGE_VEHICLE) + height += 4; + + x += w->x; + y += w->y; + + dpi = clip_drawpixelinfo(dpi, x, width, y, height); + if (dpi == NULL) + return; + + x = (widget->right - widget->left) / 2; + y = (widget->bottom - widget->top) - 12; + + ride = GET_RIDE(w->number); + RCT2_CALLPROC_X(0x006DE4CD, (ride->num_cars_per_train << 8) | ride->subtype, 0, 0, 0, 0, 0, 0); + + rideEntry = ride_get_entry(ride); + if (rideEntry->var_008 & 1) { + dpi->zoom_level = 1; + dpi->width *= 2; + dpi->height *= 2; + x *= 2; + y *= 2; + dpi->x *= 2; + dpi->y *= 2; + } + + ebp = (uint8*)rideEntry + (RCT2_ADDRESS(0x00F64E38, uint8)[rideEntry->var_013] * 101); + height += RCT2_GLOBAL(ebp + 0x24, sint8); + + vehicleColour = ride_get_vehicle_colour(ride, 0); + + spriteIndex = 32; + if (w->page == WINDOW_PARK_PAGE_VEHICLE) + spriteIndex += w->frame_no; + spriteIndex /= (RCT2_GLOBAL(ebp + 0x2C, uint16) & 0x800) ? 4 : 2; + spriteIndex &= RCT2_GLOBAL(ebp + 0x1A, uint16); + spriteIndex *= RCT2_GLOBAL(ebp + 0x30, uint16); + spriteIndex += RCT2_GLOBAL(ebp + 0x32, uint32); + spriteIndex |= (vehicleColour.additional_1 << 24) | (vehicleColour.main << 19); + spriteIndex |= 0x80000000; + + gfx_draw_sprite(dpi, spriteIndex, x, y, vehicleColour.additional_2); + } +} + +/** + * + * rct2: 0x006B2F42 + */ +static void window_ride_draw_tab_customer(rct_drawpixelinfo *dpi, rct_window *w) +{ + int spriteIndex; + int widgetIndex = WIDX_TAB_1 + WINDOW_PARK_PAGE_CUSTOMER; + rct_widget *widget = &w->widgets[widgetIndex]; + + if (!(w->disabled_widgets & (1LL << widgetIndex))) { + spriteIndex = 0; + if (w->page == WINDOW_PARK_PAGE_CUSTOMER) + spriteIndex = w->var_492 & ~3; + + spriteIndex += RCT2_GLOBAL(RCT2_GLOBAL(0x00982708, uint32), uint32); + spriteIndex += 1; + spriteIndex |= 0xA9E00000; + + gfx_draw_sprite(dpi, spriteIndex, w->x + (widget->left + widget->right) / 2, w->y + widget->bottom - 6, 0); + } +} + +/** + * + * rct2: 0x006B2B35 + */ +static void window_ride_draw_tab_images(rct_drawpixelinfo *dpi, rct_window *w) +{ + window_ride_draw_tab_vehicle(dpi, w); + window_ride_draw_tab_image(dpi, w, WINDOW_PARK_PAGE_OPERATING, 5201); + window_ride_draw_tab_image(dpi, w, WINDOW_PARK_PAGE_MAINTENANCE, 5205); + window_ride_draw_tab_image(dpi, w, WINDOW_PARK_PAGE_INCOME, 5253); + window_ride_draw_tab_main(dpi, w); + window_ride_draw_tab_image(dpi, w, WINDOW_PARK_PAGE_MEASUREMENTS, 5229); + window_ride_draw_tab_image(dpi, w, WINDOW_PARK_PAGE_COLOUR, 5221); + window_ride_draw_tab_image(dpi, w, WINDOW_PARK_PAGE_GRAPHS, 5237); + window_ride_draw_tab_customer(dpi, w); + window_ride_draw_tab_image(dpi, w, WINDOW_PARK_PAGE_MUSIC, 5335); +} + +/** + * + * rct2: 0x006AEAB4 + */ +rct_window *window_ride_open(int rideIndex) +{ + rct_window *w; + rct_ride *ride; + uint8 *rideEntryIndexPtr; + int numSubTypes, quadIndex, bitIndex; + + w = window_create_auto_pos(316, 180, window_ride_page_events[0], WC_RIDE, 0x400); + w->widgets = window_ride_page_widgets[0]; + w->enabled_widgets = window_ride_page_enabled_widgets[0]; + w->number = rideIndex; + + w->page = 0; + w->var_48C = 0; + w->frame_no = 0; + w->list_information_type = 0; + w->var_492 = 0; + w->var_494 = 0; + RCT2_CALLPROC_X(0x006AEB9F, 0, 0, 0, 0, (int)w, 0, 0); + w->min_width = 316; + w->min_height = 180; + w->max_width = 500; + w->max_height = 450; + w->flags |= WF_RESIZABLE; + w->colours[0] = 1; + w->colours[1] = 26; + w->colours[2] = 11; + + ride = GET_RIDE(rideIndex); + numSubTypes = 0; + rideEntryIndexPtr = get_ride_entry_indices_for_ride_type(ride->type); + for (; *rideEntryIndexPtr != 0xFF; rideEntryIndexPtr++) { + quadIndex = *rideEntryIndexPtr >> 5; + bitIndex = *rideEntryIndexPtr & 0x1F; + if (!(RCT2_ADDRESS(0x01357424, uint32)[quadIndex] & (1 << bitIndex))) + continue; + + numSubTypes++; + } + var_496(w) = numSubTypes; + return w; +} + +/** + * + * rct2: 0x006ACC28 + */ +void window_ride_main_open(int rideIndex) +{ + rct_window *w; + + w = window_bring_to_front_by_id(WC_RIDE, rideIndex); + if (w == NULL) { + w = window_ride_open(rideIndex); + w->ride.var_482 = -1; + } + + if (RCT2_GLOBAL(0x009DE518, uint32) & (1 << 3)) { + if (w->classification == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) && + w->number == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber) + ) { + tool_cancel(); + } + } + + w->page = 0; + w->width = 316; + w->height = 180; + window_invalidate(w); + w->widgets = window_ride_page_widgets[0]; + w->enabled_widgets = 0x007DBFF4; + w->var_020 = 0; + w->event_handlers = window_ride_page_events[0]; + w->pressed_widgets = 0; + RCT2_CALLPROC_X(0x006AEB9F, 0, 0, 0, 0, (int)w, 0, 0); + window_init_scroll_widgets(w); + w->ride.view = 0; + window_ride_init_viewport(w); +} + +/** + * + * rct2: 0x006AF1D2 + */ +static void window_ride_set_page(rct_window *w, int page) +{ + int listen; + + if (RCT2_GLOBAL(0x009DE518, uint32) & (1 << 3)) + if (w->classification == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) && w->number == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber)) + tool_cancel(); + + // Set listen only to viewport + listen = 0; + if (page == WINDOW_PARK_PAGE_MAIN && w->page == WINDOW_PARK_PAGE_MAIN && w->viewport != NULL && !(w->viewport->flags & VIEWPORT_FLAG_SOUND_ON)) + listen++; + + w->page = page; + w->frame_no = 0; + w->var_492 = 0; + if (w->viewport != NULL) { + w->viewport->width = 0; + w->viewport = NULL; + } + + w->enabled_widgets = window_ride_page_enabled_widgets[page]; + w->var_020 = RCT2_ADDRESS(0x0098DD68, uint32)[page]; + w->event_handlers = window_ride_page_events[page]; + w->pressed_widgets = 0; + w->widgets = window_ride_page_widgets[page]; + RCT2_CALLPROC_X(0x006AEB9F, 0, 0, 0, 0, (int)w, 0, 0); + window_invalidate(w); + + RCT2_CALLPROC_X(w->event_handlers[WE_RESIZE], 0, 0, 0, 0, (int)w, 0, 0); + RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + + window_init_scroll_widgets(w); + window_invalidate(w); + + if (listen != 0 && w->viewport != NULL) + w->viewport->flags |= VIEWPORT_FLAG_SOUND_ON; +} + +static void window_ride_set_pressed_tab(rct_window *w) +{ + int i; + for (i = 0; i < WINDOW_PARK_PAGE_COUNT; i++) + w->pressed_widgets &= ~(1 << (WIDX_TAB_1 + i)); + w->pressed_widgets |= 1LL << (WIDX_TAB_1 + w->page); +} + +static void window_ride_anchor_border_widgets(rct_window *w) +{ + w->widgets[WIDX_BACKGROUND].right = w->width - 1; + w->widgets[WIDX_BACKGROUND].bottom = w->height - 1; + w->widgets[WIDX_PAGE_BACKGROUND].right = w->width - 1; + w->widgets[WIDX_PAGE_BACKGROUND].bottom = w->height - 1; + w->widgets[WIDX_TITLE].right = w->width - 2; + w->widgets[WIDX_CLOSE].left = w->width - 13; + w->widgets[WIDX_CLOSE].right = w->width - 3; +} + +#pragma region Main + +/** + * + * rct2: 0x006AF994 + */ +static void window_ride_init_viewport(rct_window *w) +{ + if (w->page != WINDOW_PARK_PAGE_MAIN) return; + + rct_ride* ride = GET_RIDE(w->number); + int eax = w->viewport_focus_coordinates.var_480 - 1; + + union{ + sprite_focus sprite; + coordinate_focus coordinate; + } focus; + + focus.sprite.sprite_id = -1; + focus.coordinate.zoom = 0; + focus.coordinate.rotation = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8); + + + if (eax >= 0 && eax < ride->num_vehicles && ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK){ + focus.sprite.sprite_id = ride->vehicles[eax]; + + rct_ride_type* ride_entry = ride_get_entry(ride); + if (ride_entry->var_013 != 0){ + rct_vehicle* vehicle = GET_VEHICLE(focus.sprite.sprite_id); + focus.sprite.sprite_id = vehicle->next_vehicle_on_train; + } + focus.sprite.type |= 0xC0; + } + else if (eax >= ride->num_vehicles && eax < (ride->num_vehicles + ride->num_stations)){ + int stationIndex = -1; + int count = eax - ride->num_vehicles; + do { + stationIndex++; + if (ride->station_starts[stationIndex] != 0xFFFF) + count--; + } while (count >= 0); + + eax = ride->station_starts[stationIndex]; + + focus.coordinate.x = (eax & 0xFF) << 5; + focus.coordinate.y = (eax & 0xFF00) >> 3; + focus.coordinate.z = ride->station_heights[stationIndex] << 3; + focus.sprite.type |= 0x40; + } + else{ + if (eax > 0){ + w->viewport_focus_coordinates.var_480 = 0; + } + focus.coordinate.x = (ride->overall_view & 0xFF) << 5; + focus.coordinate.y = (ride->overall_view & 0xFF00) >> 3; + focus.coordinate.x += 16; + focus.coordinate.y += 16; + focus.coordinate.z = map_element_height(focus.coordinate.x, focus.coordinate.y) & 0xFFFF; + focus.sprite.type |= 0x40; + focus.coordinate.zoom = 1; + if (RCT2_GLOBAL(0x0097CF40 + (ride->type * 8), uint32) & 0x8000){ + focus.coordinate.zoom = 0; + } + } + focus.coordinate.var_480 = w->viewport_focus_coordinates.var_480; + + uint16 viewport_flags = 0; + + if (w->viewport != 0){ + if (focus.coordinate.x == w->viewport_focus_coordinates.x && + focus.coordinate.y == w->viewport_focus_coordinates.y && + focus.coordinate.z == w->viewport_focus_coordinates.z && + focus.coordinate.rotation == w->viewport_focus_coordinates.rotation && + focus.coordinate.zoom == w->viewport_focus_coordinates.zoom ) + return; + viewport_flags = w->viewport->flags; + w->viewport->width = 0; + w->viewport = 0; + + viewport_update_pointers(); + } + else{ + if (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) & 0x1) + viewport_flags |= VIEWPORT_FLAG_GRIDLINES; + } + + RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + + w->viewport_focus_coordinates.x = focus.coordinate.x; + w->viewport_focus_coordinates.y = focus.coordinate.y; + w->viewport_focus_coordinates.z = focus.coordinate.z; + w->viewport_focus_coordinates.rotation = focus.coordinate.rotation; + w->viewport_focus_coordinates.zoom = focus.coordinate.zoom; + + //rct2: 0x006aec9c only used here so brought it into the function + if (!w->viewport && ride->overall_view != 0xFFFF){ + rct_widget* view_widget = &w->widgets[WIDX_VIEWPORT]; + + int x = view_widget->left + 1 + w->x; + int y = view_widget->top + 1 + w->y; + int width = view_widget->right - view_widget->left - 1; + int height = view_widget->bottom - view_widget->top - 1; + viewport_create( + w, + x, + y, + width, + height, + focus.coordinate.zoom, + focus.coordinate.x, + focus.coordinate.y & VIEWPORT_FOCUS_Y_MASK, + focus.coordinate.z, + focus.sprite.type & VIEWPORT_FOCUS_TYPE_MASK, + focus.sprite.sprite_id); + + w->flags |= WF_2; + window_invalidate(w); + } + if (w->viewport){ + w->viewport->flags = viewport_flags; + window_invalidate(w); + } +} + +/** + * + * rct2: 0x006B4971 + */ +static void window_ride_construct(rct_window *w) +{ + int rideIndex = w->number; + + window_close_by_id(WC_RIDE_CONSTRUCTION | 0x80, rideIndex); + w = window_find_by_id(WC_RIDE, rideIndex); + if (w == NULL) + return; + + rct_map_element *trackMapElement; + int trackX, trackY; + + trackMapElement = sub_6CAF80(rideIndex, &trackX, &trackY); + if (trackMapElement == (rct_map_element*)-1) { + RCT2_CALLPROC_X(0x006CC3FB, 0, 0, 0, rideIndex, 0, 0, 0); + } else { + trackMapElement = ride_find_track_gap(trackMapElement, &trackX, &trackY); + + w = window_get_main(); + if (w != NULL && ride_try_construct(trackMapElement)) + window_scroll_to_location(w, trackX, trackY, trackMapElement->base_height * 8); + } +} + +/** + * + * rct2: 0x006AF315 + */ +static void window_ride_rename(rct_window *w) +{ + rct_ride *ride; + + ride = GET_RIDE(w->number); + RCT2_GLOBAL(0x013CE962, uint32) = ride->name_arguments; + window_show_textinput(w, WIDX_RENAME, STR_RIDE_ATTRACTION_NAME, STR_ENTER_NEW_NAME_FOR_THIS_RIDE_ATTRACTION, ride->name); +} + +/** + * + * rct2: 0x006AF3B3 + */ +static void window_ride_locate(rct_window *w) +{ + rct_window *mainWindow; + int xy, x, y, z; + + if (w->viewport->width == 0) + return; + + xy = w->ride.var_482; + z = w->ride.var_486; + if (xy == -1) + return; + + if (xy & 0x80000000) { + rct_sprite *sprite = &g_sprite_list[xy & 0xFFFF]; + x = sprite->unknown.x; + y = sprite->unknown.y; + z = sprite->unknown.z; + } else { + x = (xy & ~0xC0000000) & 0xFFFF; + y = (xy & ~0xC0000000) >> 16; + z = z >> 16; + } + + mainWindow = window_get_main(); + if (mainWindow != NULL) + window_scroll_to_location(mainWindow, x, y, z); +} + +/** + * + * rct2: 0x006B486A + */ +static void window_ride_demolish(rct_window *w) +{ + rct_window *demolishWindow; + int x, y, screenWidth, screenHeight; + + demolishWindow = window_bring_to_front_by_id(WC_DEMOLISH_RIDE_PROMPT, w->number); + if (demolishWindow != NULL) + return; + + screenWidth = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16); + screenHeight = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16); + x = screenWidth / 2 - 100; + y = max(28, screenHeight / 2 - 50); + + demolishWindow = window_create(x, y, 200, 100, (uint32*)0x0098E2E4, WC_DEMOLISH_RIDE_PROMPT, 0); + demolishWindow->widgets = (rct_widget*)0x009AEBA0; + demolishWindow->enabled_widgets = 4 | 8 | 16; + window_init_scroll_widgets(demolishWindow); + demolishWindow->flags |= WF_TRANSPARENT; + demolishWindow->number = w->number; + demolishWindow->colours[0] = 154; +} + +/** + * + * rct2: 0x006AF17E + */ +static void window_ride_main_mouseup() +{ + short widgetIndex; + rct_window *w; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + case WIDX_TAB_1: + case WIDX_TAB_2: + case WIDX_TAB_3: + case WIDX_TAB_4: + case WIDX_TAB_5: + case WIDX_TAB_6: + case WIDX_TAB_7: + case WIDX_TAB_8: + case WIDX_TAB_9: + case WIDX_TAB_10: + window_ride_set_page(w, widgetIndex - WIDX_TAB_1); + break; + case WIDX_CONSTRUCTION: + window_ride_construct(w); + break; + case WIDX_RENAME: + window_ride_rename(w); + break; + case WIDX_LOCATE: + window_ride_locate(w); + break; + case WIDX_DEMOLISH: + window_ride_demolish(w); + break; + } +} + +/** + * + * rct2: 0x006AF4A2 + */ +static void window_ride_main_resize() +{ + rct_window *w; + rct_viewport *viewport; + int width, height; + + window_get_register(w); + + w->flags |= WF_RESIZABLE; + window_set_resize(w, 316, 180, 500, 450); + + viewport = w->viewport; + if (viewport != NULL) { + width = w->width - 30; + height = w->height - 75; + if (viewport->width != width || viewport->height != height) { + viewport->width = width; + viewport->height = height; + viewport->view_width = width << viewport->zoom; + viewport->view_height = height << viewport->zoom; + } + } + + window_ride_init_viewport(w); +} + +/** + * + * rct2: 0x006AF825 + */ +static void window_ride_show_view_dropdown(rct_window *w, rct_widget *widget) +{ + rct_widget *dropdownWidget; + rct_ride *ride; + int numItems, currentItem, i, j, name; + + dropdownWidget = widget - 1; + ride = GET_RIDE(w->number); + + numItems = 1; + if (!(RCT2_GLOBAL(0x0097CF40 + (ride->type * 8), uint32) & 0x2000)) { + numItems += ride->num_stations; + numItems += ride->num_vehicles; + } + + window_dropdown_show_text_custom_width( + w->x + dropdownWidget->left, + w->y + dropdownWidget->top, + dropdownWidget->bottom - dropdownWidget->top + 1, + w->colours[1], + 0, + numItems, + widget->right - dropdownWidget->left + ); + + // First item + gDropdownItemsFormat[0] = 1142; + gDropdownItemsArgs[0] = STR_OVERALL_VIEW; + currentItem = 1; + + // Vehicles + name = RideNameConvention[ride->type].vehicle_name + 6; + for (i = 1; i <= ride->num_vehicles; i++) { + gDropdownItemsFormat[currentItem] = 1142; + gDropdownItemsArgs[currentItem] = name | (currentItem << 16); + currentItem++; + } + + // Stations + name = RideNameConvention[ride->type].station_name + 6; + for (i = 1; i <= ride->num_stations; i++) { + gDropdownItemsFormat[currentItem] = 1142; + gDropdownItemsArgs[currentItem] = name | (i << 16); + currentItem++; + } + + // Set highlighted item + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK)) { + j = 2; + for (i = 0; i < ride->num_vehicles; i++) { + RCT2_GLOBAL(0x009DED34, uint32) |= j; + j <<= 1; + } + } + + // Set checked item + gDropdownItemsChecked |= (1 << w->ride.view); +} + +/** + * + * rct2: 0x006AF64C + */ +static void window_ride_show_open_dropdown(rct_window *w, rct_widget *widget) +{ + rct_ride *ride; + int numItems, highlightedIndex, checkedIndex; + + ride = GET_RIDE(w->number); + + numItems = 0; + gDropdownItemsFormat[numItems] = 1142; + gDropdownItemsArgs[numItems] = STR_CLOSE_RIDE; + numItems++; + + if (!(RCT2_GLOBAL(0x0097CF40 + (ride->type * 8), uint32) & 0x800)) { + gDropdownItemsFormat[numItems] = 1142; + gDropdownItemsArgs[numItems] = STR_TEST_RIDE; + numItems++; + } + + gDropdownItemsFormat[numItems] = 1142; + gDropdownItemsArgs[numItems] = STR_OPEN_RIDE; + numItems++; + + window_dropdown_show_text( + w->x + widget->left, + w->y + widget->top, + widget->bottom - widget->top + 1, + w->colours[1], + 0, + numItems + ); + + checkedIndex = ride->status; + switch (ride->status) { + case RIDE_STATUS_CLOSED: + highlightedIndex = 0; + if ((ride->lifecycle_flags & RIDE_LIFECYCLE_CRASHED) || (ride->lifecycle_flags & RIDE_LIFECYCLE_11)) + break; + + highlightedIndex = 2; + if (RCT2_GLOBAL(0x0097CF40 + (ride->type * 8), uint32) & 0x800) + break; + if (ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED) + break; + + highlightedIndex = 1; + break; + case RIDE_STATUS_TESTING: + highlightedIndex = 2; + if (ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED) + break; + + highlightedIndex = 0; + break; + case RIDE_STATUS_OPEN: + highlightedIndex = 0; + break; + } + + if (checkedIndex != RIDE_STATUS_CLOSED) + checkedIndex = 3 - checkedIndex; + + if (RCT2_GLOBAL(0x0097CF40 + (ride->type * 8), uint32) & 0x800) { + if (checkedIndex != 0) + checkedIndex--; + if (highlightedIndex != 0) + highlightedIndex--; + } + + gDropdownItemsChecked |= (1 << checkedIndex); + RCT2_GLOBAL(0x009DEBA2, sint16) = highlightedIndex; +} + +/** + * + * rct2: 0x006AF1BD + */ +static void window_ride_main_mousedown(int widgetIndex, rct_window *w, rct_widget *widget) +{ + switch (widgetIndex) { + case WIDX_VIEW_DROPDOWN: + window_ride_show_view_dropdown(w, widget); + break; + case WIDX_OPEN: + window_ride_show_open_dropdown(w, widget); + break; + } +} + +/** + * + * rct2: 0x006AF300 + */ +static void window_ride_main_dropdown() +{ + rct_ride *ride; + rct_window *w; + int status; + short widgetIndex, dropdownIndex; + + window_dropdown_get_registers(w, widgetIndex, dropdownIndex); + + switch (widgetIndex) { + case WIDX_VIEW_DROPDOWN: + if (dropdownIndex == -1) { + dropdownIndex = w->ride.view; + ride = GET_RIDE(w->number); + dropdownIndex++; + if (dropdownIndex != 0 && dropdownIndex <= ride->num_vehicles && !(ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK)) + dropdownIndex = ride->num_vehicles + 1; + + if (dropdownIndex >= gDropdownNumItems) + dropdownIndex = 0; + } + + w->ride.view = dropdownIndex; + window_ride_init_viewport(w); + window_invalidate(w); + break; + case WIDX_OPEN: + if (dropdownIndex == -1) + dropdownIndex = RCT2_GLOBAL(0x009DEBA2, sint16); + + ride = GET_RIDE(w->number); + if ((RCT2_GLOBAL(0x0097CF40 + (ride->type * 8), uint32) & 0x800) && dropdownIndex != 0) + dropdownIndex++; + + switch (dropdownIndex) { + case 0: + status = RIDE_STATUS_CLOSED; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = 1004; + break; + case 1: + status = RIDE_STATUS_TESTING; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = 1003; + break; + case 2: + status = RIDE_STATUS_OPEN; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = 1002; + break; + } + + RCT2_GLOBAL(0x013CE952 + 6, uint16) = ride->overall_view; + RCT2_GLOBAL(0x013CE952 + 8, uint32) = ride->name_arguments; + game_do_command(0, 1, 0, w->number | (status << 8), GAME_COMMAND_SET_RIDE_OPEN, 0, 0); + break; + } +} + +/** + * + * rct2: 0x006AF40F + */ +static void window_ride_main_update(rct_window *w) +{ + rct_ride *ride; + int vehicleIndex; + uint16 vehicleSpriteIndex; + rct_vehicle *vehicle; + + // Update tab animation + w->frame_no++; + RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + widget_invalidate(WC_RIDE, w->number, WIDX_TAB_1); + + // Update status + ride = GET_RIDE(w->number); + if (!(ride->var_14D & 4)) { + if (w->ride.view == 0) + return; + + if (w->ride.view <= ride->num_vehicles) { + vehicleIndex = w->ride.view - 1; + vehicleSpriteIndex = ride->vehicles[vehicleIndex]; + if (vehicleSpriteIndex == 0xFFFF) + return; + + vehicle = &(g_sprite_list[vehicleSpriteIndex].vehicle); + if ( + vehicle->status != 4 && + vehicle->status != 22 && + vehicle->status != 10 && + vehicle->status != 7 + ) { + return; + } + } + } + + ride->var_14D &= ~4; + widget_invalidate(WC_RIDE, w->number, WIDX_STATUS); +} + +/** + * + * rct2: 0x006AF2F9 + */ +static void window_ride_main_textinput() +{ + uint8 result; + short widgetIndex; + rct_window *w; + char *text; + + window_textinput_get_registers(w, widgetIndex, result, text); + + if (widgetIndex != WIDX_RENAME || !result) + return; + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_CANT_RENAME_RIDE_ATTRACTION; + game_do_command(1, (w->number << 8) | 1, 0, *((int*)(text + 0)), GAME_COMMAND_SET_RIDE_NAME, *((int*)(text + 8)), *((int*)(text + 4))); + game_do_command(2, (w->number << 8) | 1, 0, *((int*)(text + 12)), GAME_COMMAND_SET_RIDE_NAME, *((int*)(text + 20)), *((int*)(text + 16))); + game_do_command(0, (w->number << 8) | 1, 0, *((int*)(text + 24)), GAME_COMMAND_SET_RIDE_NAME, *((int*)(text + 32)), *((int*)(text + 28))); +} + +/** + * + * rct2: 0x006AF55A + */ +static void window_ride_main_unknown_14() +{ + rct_window *w; + + window_get_register(w); + + window_ride_init_viewport(w); +} + +/** + * + * rct2: 0x006AECF6 + */ +static void window_ride_main_invalidate() +{ + rct_window *w; + rct_widget *widgets; + int i; + + window_get_register(w); + + widgets = window_ride_page_widgets[w->page]; + if (w->widgets != widgets) { + w->widgets = widgets; + window_init_scroll_widgets(w); + } + + window_ride_set_pressed_tab(w); + + rct_ride *ride = GET_RIDE(w->number); + w->disabled_widgets &= ~((1 << 22) | (1 << 19)); + if (ride->lifecycle_flags & (RIDE_LIFECYCLE_INDESTRUCTIBLE | RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK)) + w->disabled_widgets |= (1 << 22); + if (ride->lifecycle_flags & RIDE_LIFECYCLE_19) + w->disabled_widgets |= (1 << 19); + + RCT2_GLOBAL(0x013CE952 + 0, uint16) = ride->name; + RCT2_GLOBAL(0x013CE952 + 2, uint32) = ride->name_arguments; + window_ride_main_widgets[WIDX_OPEN].image = SPR_CLOSED + ride->status; + + window_ride_anchor_border_widgets(w); + + // Anchor main page specific widgets + window_ride_main_widgets[WIDX_VIEWPORT].right = w->width - 26; + window_ride_main_widgets[WIDX_VIEWPORT].bottom = w->height - 14; + window_ride_main_widgets[WIDX_STATUS].right = w->width - 26; + window_ride_main_widgets[WIDX_STATUS].top = w->height - 13; + window_ride_main_widgets[WIDX_STATUS].bottom = w->height - 3; + for (i = WIDX_OPEN; i <= WIDX_DEMOLISH; i++) { + window_ride_main_widgets[i].left = w->width - 25; + window_ride_main_widgets[i].right = w->width - 2; + } + window_ride_main_widgets[WIDX_VIEW].right = w->width - 60; + window_ride_main_widgets[WIDX_VIEW_DROPDOWN].right = w->width - 61; + window_ride_main_widgets[WIDX_VIEW_DROPDOWN].left = w->width - 71; + + window_align_tabs(w, WIDX_TAB_1, WIDX_TAB_10); +} + +/** + * + * rct2: 0x006AF10A + */ +static rct_string_id window_ride_get_status_overall_view(rct_window *w, void *arguments) +{ + int formatSecondary, argument; + rct_string_id stringId; + + ride_get_status(w->number, &formatSecondary, &argument); + RCT2_GLOBAL((int)arguments + 0, uint16) = formatSecondary; + RCT2_GLOBAL((int)arguments + 2, uint32) = argument; + stringId = STR_LOSS; + if (formatSecondary != STR_BROKEN_DOWN && formatSecondary != STR_CRASHED) + stringId = STR_BLACK_STRING; + + return stringId; +} + +/** + * + * rct2: 0x006AEFEF + */ +static rct_string_id window_ride_get_status_vehicle(rct_window *w, void *arguments) +{ + rct_ride *ride; + rct_vehicle *vehicle; + int vehicleIndex; + uint16 vehicleSpriteIndex; + rct_string_id stringId; + + ride = GET_RIDE(w->number); + + vehicleIndex = w->ride.view - 1; + vehicleSpriteIndex = ride->vehicles[vehicleIndex]; + if (vehicleSpriteIndex == 0xFFFF) + return 0; + + vehicle = &(g_sprite_list[vehicleSpriteIndex].vehicle); + if (vehicle->status != VEHICLE_STATUS_CRASHING && vehicle->status != VEHICLE_STATUS_CRASHED) { + int ax = vehicle->var_36 / 4; + if (ax == 216 || ax == 123 || ax == 9 || ax == 63 || ax == 147 || ax == 155) { + if ((RCT2_ADDRESS(0x01357644, uint32)[ride->type] & 0x40) && vehicle->velocity == 0) { + RCT2_GLOBAL((int)arguments + 0, uint16) = STR_STOPPED_BY_BLOCK_BRAKES; + return 1191; + } + } + } + + stringId = STR_MOVING_TO_END_OF + vehicle->status; + + // Get speed in mph + RCT2_GLOBAL((int)arguments + 2, uint16) = (abs(vehicle->velocity) * 9) >> 18; + + if (ride->type == RIDE_TYPE_MINI_GOLF) + return 0; + + if ((RCT2_GLOBAL(0x0097D4F2 + (ride->type * 8), uint16) & 0x100) && stringId <= 1104) + stringId += 23; + + RCT2_GLOBAL((int)arguments + 4, uint16) = RideNameConvention[ride->type].station_name; + RCT2_GLOBAL((int)arguments + 6, uint16) = vehicle->var_4B + 1; + if (ride->num_stations > 1) + RCT2_GLOBAL((int)arguments + 4, uint16) += 6; + + RCT2_GLOBAL((int)arguments + 0, uint16) = stringId; + return stringId != 1106 && stringId != 1107 ? 1191 : 1192; +} + +/** + * + * rct2: 0x006AEF65 + */ +static rct_string_id window_ride_get_status_station(rct_window *w, void *arguments) +{ + rct_ride *ride; + int stationIndex, count, queueLength; + rct_string_id stringId; + + ride = GET_RIDE(w->number); + + count = w->ride.view - ride->num_vehicles - 1; + stationIndex = -1; + do { + stationIndex++; + if (ride->station_starts[stationIndex] != 0xFFFF) + count--; + } while (count >= 0); + + stringId = 0; + + // Entrance / exit + if (ride->status == RIDE_STATUS_CLOSED) { + if (ride->entrances[stationIndex] == 0xFFFF) + stringId = STR_NO_ENTRANCE; + else if (ride->exits[stationIndex] == 0xFFFF) + stringId = STR_NO_EXIT; + } else { + if (ride->entrances[stationIndex] == 0xFFFF) + stringId = STR_EXIT_ONLY; + } + + // Queue length + if (stringId == 0) { + queueLength = ride->queue_length[stationIndex]; + RCT2_GLOBAL((int)arguments + 2, uint16) = queueLength; + stringId = STR_QUEUE_EMPTY; + if (queueLength == 1) + stringId++; + else if (queueLength > 1) + stringId += 2; + } + + RCT2_GLOBAL((int)arguments + 0, uint16) = stringId; + return 1191; +} + +/** + * + * rct2: 0x006AEE73 + */ +static rct_string_id window_ride_get_status(rct_window *w, void *arguments) +{ + rct_ride *ride = GET_RIDE(w->number); + + if (w->ride.view == 0) + return window_ride_get_status_overall_view(w, arguments); + if (w->ride.view <= ride->num_vehicles) + return window_ride_get_status_vehicle(w, arguments); + if (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN) + return window_ride_get_status_overall_view(w, arguments); + return window_ride_get_status_station(w, arguments); +} + +/** + * + * rct2: 0x006AEE73 + */ +static void window_ride_main_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + rct_ride *ride; + rct_widget *widget; + rct_string_id stringId; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + window_ride_draw_tab_images(dpi, w); + + // Viewport and ear icon + if (w->viewport != NULL) { + window_draw_viewport(dpi, w); + if (w->viewport->flags & VIEWPORT_FLAG_SOUND_ON) + gfx_draw_sprite(dpi, SPR_HEARING_VIEWPORT, w->x + 2, w->y + 2, 0); + } + + // View dropdown + ride = GET_RIDE(w->number); + stringId = STR_OVERALL_VIEW; + if (w->ride.view != 0) { + stringId = RideNameConvention[ride->type].vehicle_name + 6; + if (w->ride.view > ride->num_vehicles) { + RCT2_GLOBAL(0x013CE952 + 2, uint16) = w->ride.view - ride->num_vehicles; + stringId = RideNameConvention[ride->type].station_name + 6; + } else { + RCT2_GLOBAL(0x013CE952 + 2, uint16) = w->ride.view; + } + } + RCT2_GLOBAL(0x013CE952, uint16) = stringId; + + widget = &window_ride_main_widgets[WIDX_VIEW]; + gfx_draw_string_centred( + dpi, + 1193, + w->x + (widget->left + widget->right - 11) / 2, + w->y + widget->top, + 0, + (void*)0x013CE952 + ); + + // Status + widget = &window_ride_main_widgets[WIDX_STATUS]; + gfx_draw_string_centred_clipped( + dpi, + window_ride_get_status(w, (void*)0x013CE952), + (void*)0x013CE952, + 0, + w->x + (widget->left + widget->right) / 2, + w->y + widget->top - 1, + widget->right - widget->left + ); +} + +#pragma endregion + +#pragma region Vehicle + +/** + * + * rct2: 0x006B272D + */ +static void window_ride_vehicle_mouseup() +{ + short widgetIndex; + rct_window *w; + rct_ride *ride; + + window_widget_get_registers(w, widgetIndex); + + ride = GET_RIDE(w->number); + + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + case WIDX_TAB_1: + case WIDX_TAB_2: + case WIDX_TAB_3: + case WIDX_TAB_4: + case WIDX_TAB_5: + case WIDX_TAB_6: + case WIDX_TAB_7: + case WIDX_TAB_8: + case WIDX_TAB_9: + case WIDX_TAB_10: + window_ride_set_page(w, widgetIndex - WIDX_TAB_1); + break; + } +} + +/** + * + * rct2: 0x006B2ABB + */ +static void window_ride_vehicle_resize() +{ + rct_window *w; + + window_get_register(w); + + window_set_resize(w, 316, 208, 316, 208); +} + +/** + * + * rct2: 0x006B2748 + */ +static void window_ride_vehicle_mousedown(int widgetIndex, rct_window *w, rct_widget *widget) +{ + rct_widget *dropdownWidget = widget - 1; + rct_ride *ride; + rct_ride_type *rideEntry, *currentRideEntry; + rct_string_id stringId; + int i, minCars, maxCars, cars, numItems, quadIndex, bitIndex, rideEntryIndex, selectedIndex; + uint8 *rideEntryIndexPtr, *currentRideEntryIndex; + + ride = GET_RIDE(w->number); + rideEntry = ride_get_entry(ride); + + switch (widgetIndex) { + case WIDX_VEHICLE_TYPE_DROPDOWN: + rideEntryIndexPtr = get_ride_entry_indices_for_ride_type(ride->type); + currentRideEntryIndex; + + selectedIndex = -1; + numItems = 0; + for (currentRideEntryIndex = rideEntryIndexPtr; *currentRideEntryIndex != 0xFF; currentRideEntryIndex++) { + rideEntryIndex = *currentRideEntryIndex; + currentRideEntry = GET_RIDE_ENTRY(rideEntryIndex); + if (currentRideEntry->var_008 & 0x3000) + continue; + + quadIndex = rideEntryIndex >> 5; + bitIndex = rideEntryIndex & 0x1F; + if (!(RCT2_ADDRESS(0x01357424, uint32)[quadIndex] & (1 << bitIndex))) + continue; + + if (ride->subtype == rideEntryIndex) + selectedIndex = numItems; + + gDropdownItemsFormat[numItems] = 1142; + gDropdownItemsArgs[numItems] = (rideEntryIndex << 16) | currentRideEntry->name; + + numItems++; + } + + window_dropdown_show_text_custom_width( + w->x + dropdownWidget->left, + w->y + dropdownWidget->top, + dropdownWidget->bottom - dropdownWidget->top + 1, + w->colours[1], + 0x80, + numItems, + widget->right - dropdownWidget->left + ); + + gDropdownItemsChecked = (1 << selectedIndex); + break; + case WIDX_VEHICLE_TRAINS_DROPDOWN: + window_dropdown_show_text_custom_width( + w->x + dropdownWidget->left, + w->y + dropdownWidget->top, + dropdownWidget->bottom - dropdownWidget->top + 1, + w->colours[1], + 0x80, + ride->var_0CC, + widget->right - dropdownWidget->left + ); + + stringId = RideNameConvention[ride->type].vehicle_name + 4; + for (i = 0; i < 32; i++) { + gDropdownItemsFormat[i] = 1142; + gDropdownItemsArgs[i] = ((i + 1) << 16) | (i == 0 ? stringId : stringId + 1); + } + + gDropdownItemsChecked = (1 << (ride->num_vehicles - 1)); + break; + case WIDX_VEHICLE_CARS_PER_TRAIN_DROPDOWN: + minCars = (ride->var_0CD >> 4); + maxCars = (ride->var_0CD & 0x0F); + + window_dropdown_show_text_custom_width( + w->x + dropdownWidget->left, + w->y + dropdownWidget->top, + dropdownWidget->bottom - dropdownWidget->top + 1, + w->colours[1], + 0x80, + maxCars - minCars + 1, + widget->right - dropdownWidget->left + ); + + for (i = 0; i < 12; i++) { + cars = minCars + i; + + gDropdownItemsFormat[i] = 1142; + gDropdownItemsArgs[i] = 1024; + if (cars - rideEntry->var_012 > 1) + gDropdownItemsArgs[i]++; + gDropdownItemsArgs[i] |= (cars - rideEntry->var_012) << 16; + } + + gDropdownItemsChecked = (1 << (ride->num_cars_per_train - minCars)); + break; + } +} + +/** + * + * rct2: 0x006B2767 + */ +static void window_ride_vehicle_dropdown() +{ + rct_window *w; + short widgetIndex, dropdownIndex; + rct_ride *ride; + rct_ride_type *rideEntry; + + window_dropdown_get_registers(w, widgetIndex, dropdownIndex); + + if (dropdownIndex == -1) + return; + + ride = GET_RIDE(w->number); + rideEntry = ride_get_entry(ride); + + switch (widgetIndex) { + case WIDX_VEHICLE_TYPE_DROPDOWN: + dropdownIndex = (gDropdownItemsArgs[dropdownIndex] >> 16) & 0xFFFF; + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = 1018; + game_do_command(0, (2 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_9, 0, 0); + break; + case WIDX_VEHICLE_TRAINS_DROPDOWN: + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = 1020; + game_do_command(0, (0 << 8) | 1, 0, ((dropdownIndex + 1) << 8) | w->number, GAME_COMMAND_9, 0, 0); + break; + case WIDX_VEHICLE_CARS_PER_TRAIN_DROPDOWN: + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = 1019; + game_do_command(0, (1 << 8) | 1, 0, ((rideEntry->var_00F + dropdownIndex) << 8) | w->number, GAME_COMMAND_9, 0, 0); + break; + } +} + +/** + * + * rct2: 0x006B2AA1 + */ +static void window_ride_vehicle_update(rct_window *w) +{ + w->frame_no++; + RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + widget_invalidate(WC_RIDE, w->number, WIDX_TAB_2); +} + +/** + * + * rct2: 0x006B222C + */ +static void window_ride_vehicle_invalidate() +{ + rct_window *w; + rct_widget *widgets; + rct_ride *ride; + rct_ride_type *rideEntry; + rct_string_id stringId; + int carsPerTrain; + + window_get_register(w); + + widgets = window_ride_page_widgets[w->page]; + if (w->widgets != widgets) { + w->widgets = widgets; + window_init_scroll_widgets(w); + } + + window_ride_set_pressed_tab(w); + + ride = GET_RIDE(w->number); + rideEntry = ride_get_entry(ride); + + RCT2_GLOBAL(0x013CE952 + 0, uint16) = ride->name; + RCT2_GLOBAL(0x013CE952 + 2, uint32) = ride->name_arguments; + + // Widget setup + carsPerTrain = ride->num_cars_per_train - rideEntry->var_012; + + // Vehicle type + window_ride_vehicle_widgets[WIDX_VEHICLE_TYPE].image = rideEntry->name; + if (var_496(w) <= 1 && (w->enabled_widgets & (1 << WIDX_TAB_10))) { + window_ride_vehicle_widgets[WIDX_VEHICLE_TYPE].type = WWT_14; + window_ride_vehicle_widgets[WIDX_VEHICLE_TYPE_DROPDOWN].type = WWT_EMPTY; + w->enabled_widgets &= ~(1 << WIDX_VEHICLE_TYPE); + } else { + window_ride_vehicle_widgets[WIDX_VEHICLE_TYPE].type = WWT_DROPDOWN; + window_ride_vehicle_widgets[WIDX_VEHICLE_TYPE_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + w->enabled_widgets |= (1 << WIDX_VEHICLE_TYPE); + } + + // Trains + if (rideEntry->var_011 > 1) { + window_ride_vehicle_widgets[WIDX_VEHICLE_TRAINS].type = WWT_DROPDOWN; + window_ride_vehicle_widgets[WIDX_VEHICLE_TRAINS_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + } else { + window_ride_vehicle_widgets[WIDX_VEHICLE_TRAINS].type = WWT_EMPTY; + window_ride_vehicle_widgets[WIDX_VEHICLE_TRAINS_DROPDOWN].type = WWT_EMPTY; + } + + // Cars per train + if (rideEntry->var_012 + 1 < rideEntry->var_010) { + window_ride_vehicle_widgets[WIDX_VEHICLE_CARS_PER_TRAIN].image = carsPerTrain > 1 ? 1023 : 1022; + window_ride_vehicle_widgets[WIDX_VEHICLE_CARS_PER_TRAIN].type = WWT_DROPDOWN; + window_ride_vehicle_widgets[WIDX_VEHICLE_CARS_PER_TRAIN_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + } else { + window_ride_vehicle_widgets[WIDX_VEHICLE_CARS_PER_TRAIN].type = WWT_EMPTY; + window_ride_vehicle_widgets[WIDX_VEHICLE_CARS_PER_TRAIN_DROPDOWN].type = WWT_EMPTY; + } + + RCT2_GLOBAL(0x013CE952 + 6, uint16) = carsPerTrain; + stringId = RideNameConvention[ride->type].vehicle_name + 4; + if (ride->num_vehicles > 1) + stringId++; + RCT2_GLOBAL(0x013CE952 + 8, uint16) = stringId; + RCT2_GLOBAL(0x013CE952 + 10, uint16) = ride->num_vehicles; + + window_ride_anchor_border_widgets(w); + window_align_tabs(w, WIDX_TAB_1, WIDX_TAB_10); +} + +/** + * + * rct2: 0x006B23DC + */ +static void window_ride_vehicle_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + rct_ride *ride; + rct_ride_type *rideEntry; + rct_string_id stringId; + int x, y; + sint16 factor; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + window_ride_draw_tab_images(dpi, w); + + ride = GET_RIDE(w->number); + rideEntry = ride_get_entry(ride); + + x = w->x + 8; + y = w->y + 64; + + // Description + y += gfx_draw_string_left_wrapped(dpi, &rideEntry->description, x, y, 300, 1191, 0); + y += 5; + + // Capacity + stringId = rideEntry->description + 1; + gfx_draw_string_left(dpi, 3142, &stringId, 0, x, y); + y += 15; + + if (!(rideEntry->var_008 & 0x2000) && var_496(w) > 1) { + // Excitement Factor + factor = rideEntry->excitement_multipler; + gfx_draw_string_left(dpi, 3125, &factor, 0, x, y); + y += 10; + + // Intensity Factor + factor = rideEntry->intensity_multipler; + gfx_draw_string_left(dpi, 3126, &factor, 0, x, y); + y += 10; + + // Nausea Factor + factor = rideEntry->nausea_multipler; + gfx_draw_string_left(dpi, 3127, &factor, 0, x, y); + y += 10; + } +} + +typedef struct { + short x; + short y; + int sprite_index; + int tertiary_colour; +} rct_vehichle_paintinfo; + +rct_vehichle_paintinfo _sprites_to_draw[144]; + +/** + * + * rct2: 0x006B2502 + */ +static void window_ride_vehicle_scrollpaint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + rct_ride *ride; + rct_ride_type *rideEntry; + rct_widget *widget; + int x, y, startX, startY, i, j, vehicleColourIndex, spriteIndex, ebp; + rct_vehichle_paintinfo *nextSpriteToDraw, *current, tmp; + vehicle_colour vehicleColour; + + window_paint_get_registers(w, dpi); + + ride = GET_RIDE(w->number); + rideEntry = ride_get_entry(ride); + + // Background + gfx_fill_rect(dpi, dpi->x, dpi->y, dpi->x + dpi->width, dpi->y + dpi->height, 12); + + RCT2_CALLPROC_X(0x006DE4CD, (ride->num_cars_per_train << 8) | ride->subtype, 0, 0, 0, 0, 0, 0); + + widget = &window_ride_vehicle_widgets[WIDX_VEHICLE_TRAINS_PREVIEW]; + startX = max(2, ((widget->right - widget->left) - ((ride->num_vehicles - 1) * 36)) / 2 - 25); + startY = widget->bottom - widget->top - 4; + + ebp = (int)rideEntry + (RCT2_ADDRESS(0x00F64E38, uint8)[0] * 101); + startY += RCT2_GLOBAL(ebp + 0x24, sint8); + + // For each train + for (i = 0; i < ride->num_vehicles; i++) { + nextSpriteToDraw = _sprites_to_draw; + x = startX; + y = startY; + + // For each car in train + for (j = 0; j < ride->num_cars_per_train; j++) { + int ebp = (int)rideEntry + (RCT2_ADDRESS(0x00F64E38, uint8)[j] * 101); + x += RCT2_GLOBAL(ebp + 0x1E, uint32) / 17432; + y -= (RCT2_GLOBAL(ebp + 0x1E, uint32) / 2) / 17432; + + // Get colour of vehicle + switch (ride->colour_scheme_type & 3) { + case VEHICLE_COLOUR_SCHEME_SAME: + vehicleColourIndex = 0; + break; + case VEHICLE_COLOUR_SCHEME_PER_TRAIN: + vehicleColourIndex = i; + break; + case VEHICLE_COLOUR_SCHEME_PER_VEHICLE: + vehicleColourIndex = j; + break; + } + vehicleColour = ride_get_vehicle_colour(ride, vehicleColourIndex); + + spriteIndex = 16; + if (RCT2_GLOBAL(ebp + 0x2C, uint16) & 0x800) + spriteIndex /= 2; + + spriteIndex &= RCT2_GLOBAL(ebp + 0x1A, uint16); + spriteIndex *= RCT2_GLOBAL(ebp + 0x30, uint16); + spriteIndex += RCT2_GLOBAL(ebp + 0x32, uint32); + spriteIndex |= (vehicleColour.additional_1 << 24) | (vehicleColour.main << 19); + spriteIndex |= 0x80000000; + + nextSpriteToDraw->x = x; + nextSpriteToDraw->y = y; + nextSpriteToDraw->sprite_index = spriteIndex; + nextSpriteToDraw->tertiary_colour = vehicleColour.additional_2; + nextSpriteToDraw++; + + x += RCT2_GLOBAL(ebp + 0x1E, uint32) / 17432; + y -= (RCT2_GLOBAL(ebp + 0x1E, uint32) / 2) / 17432; + } + + if (ride->type == RIDE_TYPE_REVERSER_ROLLER_COASTER) { + tmp = *(nextSpriteToDraw - 1); + *(nextSpriteToDraw - 1) = *(nextSpriteToDraw - 2); + *(nextSpriteToDraw - 2) = tmp; + } + + current = nextSpriteToDraw; + while (--current >= _sprites_to_draw) + gfx_draw_sprite(dpi, current->sprite_index, current->x, current->y, current->tertiary_colour); + + startX += 36; + } +} + +#pragma endregion + +#pragma region Operating + +static void set_operating_setting(int rideNumber, uint8 setting, uint8 value) +{ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_CANT_CHANGE_OPERATING_MODE; + game_do_command(0, (value << 8) | 1, 0, (setting << 8) | rideNumber, GAME_COMMAND_11, 0, 0); +} + +static void window_ride_mode_tweak_set(rct_window *w, uint8 value) +{ + rct_ride *ride = GET_RIDE(w->number); + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = 1362; + if (ride->mode == RIDE_MODE_STATION_TO_STATION) + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = 1361; + if (ride->mode == RIDE_MODE_RACE) + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = 1738; + if (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x2000) + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = 1746; + if (ride->mode == RIDE_MODE_BUMPERCAR) + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = 1751; + if (ride->mode == RIDE_MODE_SWING) + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = 1768; + if (ride->mode == RIDE_MODE_ROTATION) + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = 1868; + if ( + ride->mode == RIDE_MODE_ROTATION || + ride->mode == RIDE_MODE_FORWARD_ROTATION || + ride->mode == RIDE_MODE_BACKWARD_ROTATION + ) + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = 1868; + + game_do_command(0, (value << 8) | 1, 0, (4 << 8) | w->number, GAME_COMMAND_11, 0, 0); +} + +/** + * + * rct2: 0x006B11D5 + */ +static void window_ride_mode_tweak_increase(rct_window *w) +{ + rct_ride *ride = GET_RIDE(w->number); + uint8 value = ride->var_0D0; + if (value < RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8) + 5, uint8)) + value += ride->mode == RIDE_MODE_BUMPERCAR ? 10 : 1; + + window_ride_mode_tweak_set(w, value); +} + +/** + * + * rct2: 0x006B120A + */ +static void window_ride_mode_tweak_decrease(rct_window *w) +{ + rct_ride *ride = GET_RIDE(w->number); + uint8 value = ride->var_0D0; + if (value > RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8) + 4, uint8)) + value -= ride->mode == RIDE_MODE_BUMPERCAR ? 10 : 1; + + window_ride_mode_tweak_set(w, value); +} + +/** + * + * rct2: 0x006B1631 + */ +static void window_ride_mode_dropdown(rct_window *w, rct_widget *widget) +{ + rct_ride_type *rideEntry; + rct_widget *dropdownWidget; + rct_ride *ride; + const uint8 *availableModes, *mode; + int i, numAvailableModes; + + dropdownWidget = widget - 1; + ride = GET_RIDE(w->number); + rideEntry = ride_get_entry(ride); + + // Seek to available modes for this ride + availableModes = RideAvailableModes; + for (i = 0; i < ride->type; i++) { + while (*(availableModes++) != 255) { } + } + + // Count number of available modes + mode = availableModes; + numAvailableModes = -1; + do { + numAvailableModes++; + } while (*(mode++) != 255); + + // ? + if (rideEntry->var_008 & 0x8000) + numAvailableModes--; + + // ? + if (rideEntry->var_008 & 0x20000) { + availableModes += 2; + numAvailableModes -= 2; + } + + // Create dropdown list + for (i = 0; i < numAvailableModes; i++) { + gDropdownItemsFormat[i] = 1142; + gDropdownItemsArgs[i] = STR_RIDE_MODE_START + availableModes[i]; + } + window_dropdown_show_text_custom_width( + w->x + dropdownWidget->left, + w->y + dropdownWidget->top, + dropdownWidget->bottom - dropdownWidget->top + 1, + w->colours[1], + 0, + numAvailableModes, + widget->right - dropdownWidget->left + ); + + // Set checked item + for (i = 0; i < numAvailableModes; i++) + if (ride->mode == availableModes[i]) + gDropdownItemsChecked = 1 << i; +} + +/** + * + * rct2: 0x006B15C0 + */ +static void window_ride_load_dropdown(rct_window *w, rct_widget *widget) +{ + rct_widget *dropdownWidget; + int i; + + dropdownWidget = widget - 1; + rct_ride *ride = GET_RIDE(w->number); + + for (i = 0; i < 5; i++) { + gDropdownItemsFormat[i] = 1142; + gDropdownItemsArgs[i] = STR_QUARTER_LOAD + i; + } + window_dropdown_show_text_custom_width( + w->x + dropdownWidget->left, + w->y + dropdownWidget->top, + dropdownWidget->bottom - dropdownWidget->top + 1, + w->colours[1], + 0, + 5, + widget->right - dropdownWidget->left + ); + + gDropdownItemsChecked = (1 << (ride->depart_flags & RIDE_DEPART_WAIT_FOR_LOAD_MASK)); +} + +/** + * + * rct2: 0x006B10A7 + */ +static void window_ride_operating_mouseup() +{ + short widgetIndex; + rct_window *w; + rct_ride *ride; + + window_widget_get_registers(w, widgetIndex); + + ride = GET_RIDE(w->number); + + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + case WIDX_TAB_1: + case WIDX_TAB_2: + case WIDX_TAB_3: + case WIDX_TAB_4: + case WIDX_TAB_5: + case WIDX_TAB_6: + case WIDX_TAB_7: + case WIDX_TAB_8: + case WIDX_TAB_9: + case WIDX_TAB_10: + window_ride_set_page(w, widgetIndex - WIDX_TAB_1); + break; + case WIDX_LOAD_CHECKBOX: + set_operating_setting(w->number, 1, ride->depart_flags ^ RIDE_DEPART_WAIT_FOR_LOAD); + break; + case WIDX_LEAVE_WHEN_ANOTHER_ARRIVES_CHECKBOX: + set_operating_setting(w->number, 1, ride->depart_flags ^ RIDE_DEPART_LEAVE_WHEN_ANOTHER_ARRIVES); + break; + case WIDX_MINIMUM_LENGTH_CHECKBOX: + set_operating_setting(w->number, 1, ride->depart_flags ^ RIDE_DEPART_WAIT_FOR_MINIMUM_LENGTH); + break; + case WIDX_MAXIMUM_LENGTH_CHECKBOX: + set_operating_setting(w->number, 1, ride->depart_flags ^ RIDE_DEPART_WAIT_FOR_MAXIMUM_LENGTH); + break; + case WIDX_SYNCHRONISE_WITH_ADJACENT_STATIONS_CHECKBOX: + set_operating_setting(w->number, 1, ride->depart_flags ^ RIDE_DEPART_SYNCHRONISE_WITH_ADJACENT_STATIONS); + break; + } +} + +/** + * + * rct2: 0x006B1715 + */ +static void window_ride_operating_resize() +{ + rct_window *w; + + window_get_register(w); + + window_set_resize(w, 316, 186, 316, 186); +} + +/** + * + * rct2: 0x006B10F4 + */ +static void window_ride_operating_mousedown(int widgetIndex, rct_window *w, rct_widget *widget) +{ + rct_ride *ride = GET_RIDE(w->number); + + switch (widgetIndex) { + case WIDX_MODE_TWEAK_INCREASE: + window_ride_mode_tweak_increase(w); + break; + case WIDX_MODE_TWEAK_DECREASE: + window_ride_mode_tweak_decrease(w); + break; + case WIDX_LIFT_HILL_SPEED_INCREASE: + set_operating_setting(w->number, 8, min(ride->lift_hill_speed + 1, RCT2_GLOBAL(0x0097D7CA + (ride->type * 4), uint8))); + break; + case WIDX_LIFT_HILL_SPEED_DECREASE: + set_operating_setting(w->number, 8, max(RCT2_GLOBAL(0x0097D7C9 + (ride->type * 4), uint8), ride->lift_hill_speed - 1)); + break; + case WIDX_MINIMUM_LENGTH_INCREASE: + set_operating_setting(w->number, 2, min(ride->min_waiting_time + 1, 250)); + break; + case WIDX_MINIMUM_LENGTH_DECREASE: + set_operating_setting(w->number, 2, max(0, ride->min_waiting_time - 1)); + break; + case WIDX_MAXIMUM_LENGTH_INCREASE: + set_operating_setting(w->number, 3, min(ride->max_waiting_time + 1, 250)); + break; + case WIDX_MAXIMUM_LENGTH_DECREASE: + set_operating_setting(w->number, 3, max(0, ride->max_waiting_time - 1)); + break; + case WIDX_MODE_DROPDOWN: + window_ride_mode_dropdown(w, widget); + break; + case WIDX_LOAD_DROPDOWN: + window_ride_load_dropdown(w, widget); + break; + case WIDX_OPERATE_NUMBER_OF_CIRCUITS_INCREASE: + set_operating_setting(w->number, 9, min(ride->num_circuits + 1, 7)); + break; + case WIDX_OPERATE_NUMBER_OF_CIRCUITS_DECREASE: + set_operating_setting(w->number, 9, max(1, ride->num_circuits - 1)); + break; + } +} + +/** + * + * rct2: 0x006B1165 + */ +static void window_ride_operating_dropdown() +{ + rct_window *w; + short widgetIndex, dropdownIndex; + rct_ride *ride; + const uint8 *availableModes; + int i; + + window_dropdown_get_registers(w, widgetIndex, dropdownIndex); + + if (dropdownIndex == -1) + return; + + ride = GET_RIDE(w->number); + + switch (widgetIndex) { + case WIDX_MODE_DROPDOWN: + // Seek to available modes for this ride + availableModes = RideAvailableModes; + for (i = 0; i < ride->type; i++) { + while (*(availableModes++) != 255) { } + } + set_operating_setting(w->number, 0, availableModes[dropdownIndex]); + break; + case WIDX_LOAD_DROPDOWN: + set_operating_setting(w->number, 1, (ride->depart_flags & ~RIDE_DEPART_WAIT_FOR_LOAD_MASK) | dropdownIndex); + break; + } +} + +/** + * + * rct2: 0x006B178E + */ +static void window_ride_operating_update(rct_window *w) +{ + rct_ride *ride; + + w->frame_no++; + RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + widget_invalidate(WC_RIDE, w->number, WIDX_TAB_3); + + ride = GET_RIDE(w->number); + if (ride->var_14D & 10) { + ride->var_14D &= ~10; + window_invalidate(w); + } +} + +/** + * + * rct2: 0x006B0B30 + */ +static void window_ride_operating_invalidate() +{ + rct_window *w; + rct_widget *widgets; + rct_ride *ride; + rct_ride_type *rideEntry; + rct_string_id format, caption, tooltip; + + window_get_register(w); + + widgets = window_ride_page_widgets[w->page]; + if (w->widgets != widgets) { + w->widgets = widgets; + window_init_scroll_widgets(w); + } + + window_ride_set_pressed_tab(w); + + ride = GET_RIDE(w->number); + rideEntry = ride_get_entry(ride); + + RCT2_GLOBAL(0x013CE952 + 0, uint16) = ride->name; + RCT2_GLOBAL(0x013CE952 + 2, uint32) = ride->name_arguments; + + // Widget setup + w->pressed_widgets &= ~0x44700000; + + // Lift hill speed + if ((rideEntry->var_1B6 & RCT2_ADDRESS(0x01357444, uint32)[ride->type]) & 8) { + window_ride_operating_widgets[WIDX_LIFT_HILL_SPEED_LABEL].type = WWT_24; + window_ride_operating_widgets[WIDX_LIFT_HILL_SPEED].type = WWT_SPINNER; + window_ride_operating_widgets[WIDX_LIFT_HILL_SPEED_INCREASE].type = WWT_DROPDOWN_BUTTON; + window_ride_operating_widgets[WIDX_LIFT_HILL_SPEED_DECREASE].type = WWT_DROPDOWN_BUTTON; + RCT2_GLOBAL(0x013CE966, uint16) = ride->lift_hill_speed; + } else { + window_ride_operating_widgets[WIDX_LIFT_HILL_SPEED_LABEL].type = WWT_EMPTY; + window_ride_operating_widgets[WIDX_LIFT_HILL_SPEED].type = WWT_EMPTY; + window_ride_operating_widgets[WIDX_LIFT_HILL_SPEED_INCREASE].type = WWT_EMPTY; + window_ride_operating_widgets[WIDX_LIFT_HILL_SPEED_DECREASE].type = WWT_EMPTY; + } + + // Number of circuits + if (ride_can_have_multiple_circuits(ride)) { + window_ride_operating_widgets[WIDX_OPERATE_NUMBER_OF_CIRCUITS_LABEL].type = WWT_24; + window_ride_operating_widgets[WIDX_OPERATE_NUMBER_OF_CIRCUITS].type = WWT_SPINNER; + window_ride_operating_widgets[WIDX_OPERATE_NUMBER_OF_CIRCUITS_INCREASE].type = WWT_DROPDOWN_BUTTON; + window_ride_operating_widgets[WIDX_OPERATE_NUMBER_OF_CIRCUITS_DECREASE].type = WWT_DROPDOWN_BUTTON; + RCT2_GLOBAL(0x013CE968, uint16) = ride->num_circuits; + } else { + window_ride_operating_widgets[WIDX_OPERATE_NUMBER_OF_CIRCUITS_LABEL].type = WWT_EMPTY; + window_ride_operating_widgets[WIDX_OPERATE_NUMBER_OF_CIRCUITS].type = WWT_EMPTY; + window_ride_operating_widgets[WIDX_OPERATE_NUMBER_OF_CIRCUITS_INCREASE].type = WWT_EMPTY; + window_ride_operating_widgets[WIDX_OPERATE_NUMBER_OF_CIRCUITS_DECREASE].type = WWT_EMPTY; + } + + // Leave if another vehicle arrives at station + if ( + (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x10) && + ride->num_vehicles > 1 && + ride->mode != RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED && + ride->mode != RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED + ) { + window_ride_operating_widgets[WIDX_LEAVE_WHEN_ANOTHER_ARRIVES_CHECKBOX].type = WWT_CHECKBOX; + window_ride_operating_widgets[WIDX_LEAVE_WHEN_ANOTHER_ARRIVES_CHECKBOX].tooltip = STR_LEAVE_IF_ANOTHER_VEHICLE_ARRIVES_TIP; + window_ride_operating_widgets[WIDX_LEAVE_WHEN_ANOTHER_ARRIVES_CHECKBOX].image = RideNameConvention[ride->type].vehicle_name == 1236 ? + STR_LEAVE_IF_ANOTHER_BOAT_ARRIVES : + STR_LEAVE_IF_ANOTHER_TRAIN_ARRIVES; + } else { + window_ride_operating_widgets[WIDX_LEAVE_WHEN_ANOTHER_ARRIVES_CHECKBOX].type = WWT_EMPTY; + } + + // Synchronise with adjacent stations + if (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x20) { + window_ride_operating_widgets[WIDX_SYNCHRONISE_WITH_ADJACENT_STATIONS_CHECKBOX].type = WWT_CHECKBOX; + window_ride_operating_widgets[WIDX_SYNCHRONISE_WITH_ADJACENT_STATIONS_CHECKBOX].image = STR_SYNCHRONISE_WITH_ADJACENT_STATIONS; + window_ride_operating_widgets[WIDX_SYNCHRONISE_WITH_ADJACENT_STATIONS_CHECKBOX].tooltip = STR_SYNCHRONISE_WITH_ADJACENT_STATIONS_TIP; + } else { + window_ride_operating_widgets[WIDX_SYNCHRONISE_WITH_ADJACENT_STATIONS_CHECKBOX].type = WWT_EMPTY; + } + + // Mode + window_ride_operating_widgets[WIDX_MODE].image = STR_RIDE_MODE_START + ride->mode; + + // Waiting + window_ride_operating_widgets[WIDX_LOAD].image = STR_QUARTER_LOAD + (ride->depart_flags & RIDE_DEPART_WAIT_FOR_LOAD_MASK); + if (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x4000) { + window_ride_operating_widgets[WIDX_LOAD_CHECKBOX].type = WWT_CHECKBOX; + window_ride_operating_widgets[WIDX_LOAD].type = WWT_DROPDOWN; + window_ride_operating_widgets[WIDX_LOAD_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + + window_ride_operating_widgets[WIDX_MINIMUM_LENGTH_CHECKBOX].type = WWT_CHECKBOX; + window_ride_operating_widgets[WIDX_MINIMUM_LENGTH].type = WWT_SPINNER; + window_ride_operating_widgets[WIDX_MINIMUM_LENGTH_INCREASE].type = WWT_DROPDOWN_BUTTON; + window_ride_operating_widgets[WIDX_MINIMUM_LENGTH_DECREASE].type = WWT_DROPDOWN_BUTTON; + + window_ride_operating_widgets[WIDX_MAXIMUM_LENGTH_CHECKBOX].type = WWT_CHECKBOX; + window_ride_operating_widgets[WIDX_MAXIMUM_LENGTH].type = WWT_SPINNER; + window_ride_operating_widgets[WIDX_MAXIMUM_LENGTH_INCREASE].type = WWT_DROPDOWN_BUTTON; + window_ride_operating_widgets[WIDX_MAXIMUM_LENGTH_DECREASE].type = WWT_DROPDOWN_BUTTON; + + RCT2_GLOBAL(0x013CE952 + 10, uint16) = 1217; + RCT2_GLOBAL(0x013CE95E, uint16) = ride->min_waiting_time; + RCT2_GLOBAL(0x013CE960, uint16) = 1217; + RCT2_GLOBAL(0x013CE962, uint16) = ride->max_waiting_time; + + if (ride->depart_flags & RIDE_DEPART_WAIT_FOR_LOAD) + w->pressed_widgets |= (1 << WIDX_LOAD_CHECKBOX); + } else { + window_ride_operating_widgets[WIDX_LOAD_CHECKBOX].type = WWT_EMPTY; + window_ride_operating_widgets[WIDX_LOAD].type = WWT_EMPTY; + window_ride_operating_widgets[WIDX_LOAD_DROPDOWN].type = WWT_EMPTY; + + window_ride_operating_widgets[WIDX_MINIMUM_LENGTH_CHECKBOX].type = WWT_EMPTY; + window_ride_operating_widgets[WIDX_MINIMUM_LENGTH].type = WWT_EMPTY; + window_ride_operating_widgets[WIDX_MINIMUM_LENGTH_INCREASE].type = WWT_EMPTY; + window_ride_operating_widgets[WIDX_MINIMUM_LENGTH_DECREASE].type = WWT_EMPTY; + + window_ride_operating_widgets[WIDX_MAXIMUM_LENGTH_CHECKBOX].type = WWT_EMPTY; + window_ride_operating_widgets[WIDX_MAXIMUM_LENGTH].type = WWT_EMPTY; + window_ride_operating_widgets[WIDX_MAXIMUM_LENGTH_INCREASE].type = WWT_EMPTY; + window_ride_operating_widgets[WIDX_MAXIMUM_LENGTH_DECREASE].type = WWT_EMPTY; + } + + if (ride->depart_flags & RIDE_DEPART_LEAVE_WHEN_ANOTHER_ARRIVES) + w->pressed_widgets |= (1 << WIDX_LEAVE_WHEN_ANOTHER_ARRIVES_CHECKBOX); + if (ride->depart_flags & RIDE_DEPART_SYNCHRONISE_WITH_ADJACENT_STATIONS) + w->pressed_widgets |= (1 << WIDX_SYNCHRONISE_WITH_ADJACENT_STATIONS_CHECKBOX); + if (ride->depart_flags & RIDE_DEPART_WAIT_FOR_MINIMUM_LENGTH) + w->pressed_widgets |= (1 << WIDX_MINIMUM_LENGTH_CHECKBOX); + if (ride->depart_flags & RIDE_DEPART_WAIT_FOR_MAXIMUM_LENGTH) + w->pressed_widgets |= (1 << WIDX_MAXIMUM_LENGTH_CHECKBOX); + + // Mode specific functionality + RCT2_GLOBAL(0x013CE964, uint16) = ride->var_0D0; + switch (ride->mode) { + case RIDE_MODE_POWERED_LAUNCH: + case RIDE_MODE_POWERED_LAUNCH_35: + case RIDE_MODE_UPWARD_LAUNCH: + case RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED: + RCT2_GLOBAL(0x013CE964, uint16) = (ride->var_0D0 * 9) / 4; + format = 1331; + caption = STR_LAUNCH_SPEED; + tooltip = STR_LAUNCH_SPEED_TIP; + case RIDE_MODE_STATION_TO_STATION: + RCT2_GLOBAL(0x013CE964, uint16) = (ride->var_0D0 * 9) / 4; + caption = STR_SPEED; + tooltip = STR_SPEED_TIP; + break; + case RIDE_MODE_RACE: + RCT2_GLOBAL(0x013CE964, uint16) = ride->var_0D0; + format = 1736; + caption = STR_NUMBER_OF_LAPS; + tooltip = STR_NUMBER_OF_LAPS_TIP; + break; + case RIDE_MODE_BUMPERCAR: + format = 1749; + caption = STR_TIME_LIMIT; + tooltip = STR_TIME_LIMIT_TIP; + break; + case RIDE_MODE_SWING: + format = 1771; + caption = STR_NUMBER_OF_SWINGS; + tooltip = STR_NUMBER_OF_SWINGS_TIP; + break; + case RIDE_MODE_ROTATION: + case RIDE_MODE_FORWARD_ROTATION: + case RIDE_MODE_BACKWARD_ROTATION: + format = 1871; + caption = STR_NUMBER_OF_ROTATIONS; + tooltip = STR_NUMBER_OF_ROTATIONS_TIP; + break; + default: + format = 1736; + caption = STR_MAX_PEOPLE_ON_RIDE; + tooltip = STR_MAX_PEOPLE_ON_RIDE_TIP; + if (!(RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x2000)) + format = 0; + break; + } + + if (format != 0) { + if (ride->type == RIDE_TYPE_TWIST) + RCT2_GLOBAL(0x013CE964, uint16) *= 3; + + window_ride_operating_widgets[WIDX_MODE_TWEAK_LABEL].type = WWT_24; + window_ride_operating_widgets[WIDX_MODE_TWEAK_LABEL].image = caption; + window_ride_operating_widgets[WIDX_MODE_TWEAK_LABEL].tooltip = tooltip; + window_ride_operating_widgets[WIDX_MODE_TWEAK].type = WWT_SPINNER; + window_ride_operating_widgets[WIDX_MODE_TWEAK].image = format; + window_ride_operating_widgets[WIDX_MODE_TWEAK_INCREASE].type = WWT_DROPDOWN_BUTTON; + window_ride_operating_widgets[WIDX_MODE_TWEAK_DECREASE].type = WWT_DROPDOWN_BUTTON; + w->pressed_widgets &= ~(1 << WIDX_LEAVE_WHEN_ANOTHER_ARRIVES_CHECKBOX); + } else { + window_ride_operating_widgets[WIDX_MODE_TWEAK_LABEL].type = WWT_EMPTY; + window_ride_operating_widgets[WIDX_MODE_TWEAK].type = WWT_EMPTY; + window_ride_operating_widgets[WIDX_MODE_TWEAK_INCREASE].type = WWT_EMPTY; + window_ride_operating_widgets[WIDX_MODE_TWEAK_DECREASE].type = WWT_EMPTY; + } + + window_ride_anchor_border_widgets(w); + window_align_tabs(w, WIDX_TAB_1, WIDX_TAB_10); +} + +/** + * + * rct2: 0x006B1001 + */ +static void window_ride_operating_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + rct_ride *ride; + uint16 blockSections; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + window_ride_draw_tab_images(dpi, w); + + ride = GET_RIDE(w->number); + + // Horizontal rule between mode settings and depart settings + gfx_fill_rect_inset( + dpi, + w->x + window_ride_operating_widgets[WIDX_PAGE_BACKGROUND].left + 4, + w->y + 103, + w->x + window_ride_operating_widgets[WIDX_PAGE_BACKGROUND].right - 5, + w->y + 104, + w->colours[1], + 0x20 + ); + + // Number of block sections + if (ride->mode == RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED || ride->mode == RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED) { + blockSections = ride->num_block_brakes + ride->num_stations; + gfx_draw_string_left(dpi, STR_BLOCK_SECTIONS, &blockSections, 0, w->x + 21, ride->mode == 36 ? w->y + 76 : w->y + 61); + } +} + +#pragma endregion + +#pragma region Maintenance + +/** + * + * rct2: 0x006B1AE4 + */ +static void window_ride_locate_mechanic(rct_window *w) +{ + rct_peep *peep; + rct_ride *ride = GET_RIDE(w->number); + + peep = ride_get_assigned_mechanic(ride); + if (peep != NULL) { + window_staff_open(peep); + } else { + // Presumebly looks for the closest mechanic + RCT2_CALLPROC_X(0x006B1B3E, 0, w->number * 0x260, 0, 0, (int)w, 0, 0); + } +} + +/** + * + * rct2: 0x006B7D08 + */ +static void window_ride_maintenance_draw_bar(rct_window *w, rct_drawpixelinfo *dpi, int x, int y, int value, int unk) +{ + gfx_fill_rect_inset(dpi, x, y, x + 149, y + 8, w->colours[1], 0x30); + if (unk & (1 << 31)) { + unk &= ~(1 << 31); + if (RCT2_GLOBAL(0x009DEA6E, uint8) == 0 && (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) & 8)) + return; + } + + value = ((186 * ((value * 2) & 0xFF)) >> 8) & 0xFF; + if (value > 2) { + gfx_fill_rect_inset(dpi, x + 2, y + 1, x + value + 1, y + 8, unk, 0); + } +} + +/** + * + * rct2: 0x006B1AAD + */ +static void window_ride_maintenance_mouseup() +{ + short widgetIndex; + rct_window *w; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + case WIDX_TAB_1: + case WIDX_TAB_2: + case WIDX_TAB_3: + case WIDX_TAB_4: + case WIDX_TAB_5: + case WIDX_TAB_6: + case WIDX_TAB_7: + case WIDX_TAB_8: + case WIDX_TAB_9: + case WIDX_TAB_10: + window_ride_set_page(w, widgetIndex - WIDX_TAB_1); + break; + case WIDX_LOCATE_MECHANIC: + window_ride_locate_mechanic(w); + break; + } +} + +/** + * + * rct2: 0x006B1D70 + */ +static void window_ride_maintenance_resize() +{ + rct_window *w; + + window_get_register(w); + + window_set_resize(w, 316, 135, 316, 135); +} + +/** + * + * rct2: 0x006B1ACE + */ +static void window_ride_maintenance_mousedown(int widgetIndex, rct_window *w, rct_widget *widget) +{ + rct_widget *dropdownWidget; + int i; + + if (widgetIndex != WIDX_INSPECTION_INTERVAL_DROPDOWN) + return; + + dropdownWidget = widget - 1; + rct_ride *ride = GET_RIDE(w->number); + + for (i = 0; i < 7; i++) { + gDropdownItemsFormat[i] = 1142; + gDropdownItemsArgs[i] = STR_EVERY_10_MINUTES + i; + } + window_dropdown_show_text_custom_width( + w->x + dropdownWidget->left, + w->y + dropdownWidget->top, + dropdownWidget->bottom - dropdownWidget->top + 1, + w->colours[1], + 0, + 7, + widget->right - dropdownWidget->left + ); + + gDropdownItemsChecked = (1 << ride->inspection_interval); +} + +/** + * + * rct2: 0x006B1AD9 + */ +static void window_ride_maintenance_dropdown() +{ + rct_window *w; + rct_ride *ride; + short widgetIndex, dropdownIndex; + + window_dropdown_get_registers(w, widgetIndex, dropdownIndex); + + if (widgetIndex != WIDX_INSPECTION_INTERVAL_DROPDOWN || dropdownIndex == -1) + return; + + ride = GET_RIDE(w->number); + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_CANT_CHANGE_OPERATING_MODE; + game_do_command(0, (dropdownIndex << 8) | 1, 0, (5 << 8) | w->number, GAME_COMMAND_11, 0, 0); +} + +/** + * + * rct2: 0x006B1D37 + */ +static void window_ride_maintenance_update(rct_window *w) +{ + rct_ride *ride; + + w->frame_no++; + RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + widget_invalidate(WC_RIDE, w->number, WIDX_TAB_4); + + ride = GET_RIDE(w->number); + if (ride->var_14D & 20) { + ride->var_14D &= ~20; + window_invalidate(w); + } +} + +/** + * + * rct2: 0x006B17C8 + */ +static void window_ride_maintenance_invalidate() +{ + rct_window *w; + rct_widget *widgets; + + window_get_register(w); + + widgets = window_ride_page_widgets[w->page]; + if (w->widgets != widgets) { + w->widgets = widgets; + window_init_scroll_widgets(w); + } + + window_ride_set_pressed_tab(w); + + rct_ride *ride = GET_RIDE(w->number); + RCT2_GLOBAL(0x013CE952 + 0, uint16) = ride->name; + RCT2_GLOBAL(0x013CE952 + 2, uint32) = ride->name_arguments; + + window_ride_maintenance_widgets[WIDX_INSPECTION_INTERVAL].image = STR_EVERY_10_MINUTES + ride->inspection_interval; + + window_ride_anchor_border_widgets(w); + window_align_tabs(w, WIDX_TAB_1, WIDX_TAB_10); +} + +/** + * + * rct2: 0x006B1877 + */ +static void window_ride_maintenance_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + rct_ride *ride; + rct_widget *widget; + rct_peep *mechanicSprite; + int x, y; + uint16 reliability, downTime, lastInspection; + rct_string_id stringId, breakdownMessage; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + window_ride_draw_tab_images(dpi, w); + + ride = GET_RIDE(w->number); + + // Locate mechanic button image + widget = &window_ride_maintenance_widgets[WIDX_LOCATE_MECHANIC]; + x = w->x + widget->left; + y = w->y + widget->top; + gfx_draw_sprite(dpi, (RCT2_GLOBAL(RCT2_ADDRESS_MECHANIC_COLOUR, uint8) << 24) | 0xA0000000 | 5196, x, y, 0); + + // Inspection label + widget = &window_ride_maintenance_widgets[WIDX_INSPECTION_INTERVAL]; + x = w->x + 4; + y = w->y + widget->top + 1; + gfx_draw_string_left(dpi, STR_INSPECTION, NULL, 0, x, y); + + // Reliability + widget = &window_ride_maintenance_widgets[WIDX_PAGE_BACKGROUND]; + x = w->x + widget->left + 4; + y = w->y + widget->top + 4; + + reliability = ride->var_196 >> 8; + gfx_draw_string_left(dpi, STR_RELIABILITY_LABEL_1757, &reliability, 0, x, y); + window_ride_maintenance_draw_bar(w, dpi, x + 103, y, max(10, reliability), 14); + y += 11; + + // Down time + downTime = ride->var_199; + gfx_draw_string_left(dpi, STR_DOWN_TIME_LABEL_1889, &downTime, 0, x, y); + window_ride_maintenance_draw_bar(w, dpi, x + 103, y, downTime, 28); + y += 26; + + // Last inspection + lastInspection = ride->last_inspection; + stringId = lastInspection <= 240 ? + STR_TIME_SINCE_LAST_INSPECTION_MINUTES : + STR_TIME_SINCE_LAST_INSPECTION_MORE_THAN_4_HOURS; + gfx_draw_string_left(dpi, stringId, &lastInspection, 0, x, y); + y += 12; + + // Last / current breakdown + if (ride->breakdown_reason == BREAKDOWN_NONE) + return; + + stringId = (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN) ? + STR_CURRENT_BREAKDOWN : + STR_LAST_BREAKDOWN; + breakdownMessage = STR_SAFETY_CUT_OUT + ride->breakdown_reason; + gfx_draw_string_left(dpi, stringId, &breakdownMessage, 0, x, y); + y += 10; + + // Mechanic status + if (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN) { + switch (ride->mechanic_status) { + case RIDE_MECHANIC_STATUS_CALLING: + stringId = STR_CALLING_MECHANIC; + break; + case RIDE_MECHANIC_STATUS_HEADING: + stringId = STR_MEHCANIC_IS_HEADING_FOR_THE_RIDE; + break; + case RIDE_MECHANIC_STATUS_FIXING: + case 4: + stringId = STR_MEHCANIC_IS_FIXING_THE_RIDE; + break; + default: + stringId = 0; + break; + } + + if (stringId != 0) { + if (stringId == STR_CALLING_MECHANIC) { + gfx_draw_string_left_wrapped(dpi, NULL, x + 4, y, 280, stringId, 0); + } else { + mechanicSprite = &(g_sprite_list[ride->mechanic].peep); + if (peep_is_mechanic(mechanicSprite)) { + RCT2_GLOBAL(0x013CE952 + 0, uint16) = mechanicSprite->name_string_idx; + RCT2_GLOBAL(0x013CE952 + 2, uint32) = mechanicSprite->id; + gfx_draw_string_left_wrapped(dpi, (void*)0x013CE952, x + 4, y, 280, stringId, 0); + } + } + } + } +} + +#pragma endregion + +#pragma region Colour + +const uint8 window_ride_entrance_style_list[] = { + RIDE_ENTRANCE_STYLE_PLAIN, + RIDE_ENTRANCE_STYLE_CANVAS_TENT, + RIDE_ENTRANCE_STYLE_WOODEN, + RIDE_ENTRANCE_STYLE_CASTLE_BROWN, + RIDE_ENTRANCE_STYLE_CASTLE_GREY, + RIDE_ENTRANCE_STYLE_LOG_CABIN, + RIDE_ENTRANCE_STYLE_JUNGLE, + RIDE_ENTRANCE_STYLE_LOG_CABIN, + RIDE_ENTRANCE_STYLE_CLASSICAL_ROMAN, + RIDE_ENTRANCE_STYLE_ABSTRACT, + RIDE_ENTRANCE_STYLE_SNOW_ICE, + RIDE_ENTRANCE_STYLE_PAGODA, + RIDE_ENTRANCE_STYLE_SPACE +}; + +static uint32 window_ride_get_colour_button_image(int colour) +{ + return 0x60000000 | (colour << 19) | 5059; +} + +static int window_ride_has_track_colour(rct_ride *ride, int trackColour) +{ + uint16 unk_1 = RCT2_GLOBAL(0x00993E20 + (ride->entrance_style * 8), uint16); + uint32 unk_2 = RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32); + + switch (trackColour) { + case 0: return ((unk_1 & 1) && !(unk_2 & 0x20000)) || (unk_2 & 1); + case 1: return ((unk_1 & 2) && !(unk_2 & 0x20000)) || (unk_2 & 2); + case 2: return unk_2 & 4; + default: return 0; + } +} + +static void window_ride_set_track_colour_scheme(rct_window *w, int x, int y) +{ + rct_map_element *mapElement; + uint8 newColourScheme; + + newColourScheme = (uint8)(*((uint16*)&w->var_494)); + + // Get map coordinates from point + int eax, ebx, ecx, edx, esi, edi, ebp; + eax = x; + ebx = y; + edx = -5; + RCT2_CALLFUNC_X(0x00685ADC, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + x = eax & 0xFFFF; + y = ecx & 0xFFFF; + mapElement = (rct_map_element*)edx; + + if ((ebx & 0xFF) != 3) + return; + if (mapElement->properties.track.ride_index != w->number) + return; + if ((mapElement->properties.track.colour & 3) == newColourScheme) + return; + + RCT2_CALLPROC_X( + 0x006C683D, + x, + ((mapElement->type & 3) << 8) | mapElement->properties.track.type, + y, + mapElement->base_height << 3, + newColourScheme, + 0, + 4 + ); +} + +/** + * + * rct2: 0x006B04FA + */ +static void window_ride_colour_close() +{ + rct_window *w; + + window_get_register(w); + + if (!(RCT2_GLOBAL(0x009DE518, uint32) & (1 << 3))) + return; + + if (RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) != w->classification) + return; + + if (RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber) != w->number) + return; + + tool_cancel(); +} + +/** + * + * rct2: 0x006B02A1 + */ +static void window_ride_colour_mouseup() +{ + short widgetIndex; + rct_window *w; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + case WIDX_TAB_1: + case WIDX_TAB_2: + case WIDX_TAB_3: + case WIDX_TAB_4: + case WIDX_TAB_5: + case WIDX_TAB_6: + case WIDX_TAB_7: + case WIDX_TAB_8: + case WIDX_TAB_9: + case WIDX_TAB_10: + window_ride_set_page(w, widgetIndex - WIDX_TAB_1); + break; + case WIDX_PAINT_INDIVIDUAL_AREA: + tool_set(w, WIDX_PAINT_INDIVIDUAL_AREA, 23); + break; + } +} + +/** + * + * rct2: 0x006B0AB6 + */ +static void window_ride_colour_resize() +{ + rct_window *w; + + window_get_register(w); + + window_set_resize(w, 316, 207, 316, 207); +} + +/** + * + * rct2: 0x006B02C6 + */ +static void window_ride_colour_mousedown(int widgetIndex, rct_window *w, rct_widget *widget) +{ + rct_ride *ride; + uint16 colourSchemeIndex; + vehicle_colour vehicleColour; + rct_widget *dropdownWidget; + rct_ride_type *rideEntry; + int i, numItems; + rct_string_id stringId; + + ride = GET_RIDE(w->number); + rideEntry = ride_get_entry(ride); + colourSchemeIndex = *((uint16*)&w->var_494); + dropdownWidget = widget - 1; + + switch (widgetIndex) { + case WIDX_TRACK_COLOUR_SCHEME_DROPDOWN: + for (i = 0; i < 4; i++) { + gDropdownItemsFormat[i] = 1142; + gDropdownItemsArgs[i] = STR_MAIN_COLOUR_SCHEME + i; + } + + window_dropdown_show_text_custom_width( + w->x + dropdownWidget->left, + w->y + dropdownWidget->top, + dropdownWidget->bottom - dropdownWidget->top + 1, + w->colours[1], + 0, + 4, + widget->right - dropdownWidget->left + ); + + gDropdownItemsChecked = 1 << colourSchemeIndex; + break; + case WIDX_TRACK_MAIN_COLOUR: + window_dropdown_show_colour(w, widget, w->colours[1], ride->track_colour_main[colourSchemeIndex]); + break; + case WIDX_TRACK_ADDITIONAL_COLOUR: + window_dropdown_show_colour(w, widget, w->colours[1], ride->track_colour_additional[colourSchemeIndex]); + break; + case WIDX_TRACK_SUPPORT_COLOUR: + window_dropdown_show_colour(w, widget, w->colours[1], ride->track_colour_supports[colourSchemeIndex]); + break; + case WIDX_MAZE_STYLE_DROPDOWN: + for (i = 0; i < 4; i++) { + gDropdownItemsFormat[i] = 1142; + gDropdownItemsArgs[i] = STR_BRICK_WALLS + i; + } + + window_dropdown_show_text_custom_width( + w->x + dropdownWidget->left, + w->y + dropdownWidget->top, + dropdownWidget->bottom - dropdownWidget->top + 1, + w->colours[1], + 0, + 4, + widget->right - dropdownWidget->left + ); + + gDropdownItemsChecked = 1 << ride->track_colour_supports[colourSchemeIndex]; + break; + case WIDX_ENTRANCE_STYLE_DROPDOWN: + for (i = 0; i < countof(window_ride_entrance_style_list); i++) { + gDropdownItemsFormat[i] = 1142; + gDropdownItemsArgs[i] = STR_PLAIN_ENTRANCE + window_ride_entrance_style_list[i]; + + if (ride->entrance_style == window_ride_entrance_style_list[i]) + gDropdownItemsChecked = 1 << i; + } + int checked = gDropdownItemsChecked; + + window_dropdown_show_text_custom_width( + w->x + dropdownWidget->left, + w->y + dropdownWidget->top, + dropdownWidget->bottom - dropdownWidget->top + 1, + w->colours[1], + 0x80, + countof(window_ride_entrance_style_list), + widget->right - dropdownWidget->left + ); + + gDropdownItemsChecked = checked; + break; + case WIDX_VEHICLE_COLOUR_SCHEME_DROPDOWN: + for (i = 0; i < 3; i++) { + gDropdownItemsFormat[i] = 1142; + gDropdownItemsArgs[i] = (RideNameConvention[ride->type].vehicle_name << 16) | (STR_ALL_VEHICLES_IN_SAME_COLOURS + i); + } + + window_dropdown_show_text_custom_width( + w->x + dropdownWidget->left, + w->y + dropdownWidget->top, + dropdownWidget->bottom - dropdownWidget->top + 1, + w->colours[1], + 0, + rideEntry->var_010 > 1 ? 3 : 2, + widget->right - dropdownWidget->left + ); + + gDropdownItemsChecked = 1 << (ride->colour_scheme_type & 3); + break; + case WIDX_VEHICLE_COLOUR_INDEX_DROPDOWN: + numItems = ride->num_vehicles; + if ((ride->colour_scheme_type & 3) != VEHICLE_COLOUR_SCHEME_PER_TRAIN) + numItems = ride->num_cars_per_train; + + stringId = (ride->colour_scheme_type & 3) == VEHICLE_COLOUR_SCHEME_PER_TRAIN ? 1135 : 1133; + for (i = 0; i < 32; i++) { + gDropdownItemsFormat[i] = 1142; + gDropdownItemsArgs[i] = ((sint64)(i + 1) << 32) | ((RideNameConvention[ride->type].vehicle_name + 2) << 16) | stringId; + } + + window_dropdown_show_text_custom_width( + w->x + dropdownWidget->left, + w->y + dropdownWidget->top, + dropdownWidget->bottom - dropdownWidget->top + 1, + w->colours[1], + 0x80, + numItems, + widget->right - dropdownWidget->left + ); + + gDropdownItemsChecked = 1 << w->var_48C; + break; + case WIDX_VEHICLE_MAIN_COLOUR: + vehicleColour = ride_get_vehicle_colour(ride, w->var_48C); + window_dropdown_show_colour(w, widget, w->colours[1], vehicleColour.main); + break; + case WIDX_VEHICLE_ADDITIONAL_COLOUR_1: + vehicleColour = ride_get_vehicle_colour(ride, w->var_48C); + window_dropdown_show_colour(w, widget, w->colours[1], vehicleColour.additional_1); + break; + case WIDX_VEHICLE_ADDITIONAL_COLOUR_2: + vehicleColour = ride_get_vehicle_colour(ride, w->var_48C); + window_dropdown_show_colour(w, widget, w->colours[1], vehicleColour.additional_2); + break; + } +} + +/** + * + * rct2: 0x006B0331 + */ +static void window_ride_colour_dropdown() +{ + rct_window *w; + short widgetIndex, dropdownIndex; + + window_dropdown_get_registers(w, widgetIndex, dropdownIndex); + + if (dropdownIndex == -1) + return; + + switch (widgetIndex) { + case WIDX_TRACK_COLOUR_SCHEME_DROPDOWN: + *((uint16*)&w->var_494) = dropdownIndex; + window_invalidate(w); + break; + case WIDX_TRACK_MAIN_COLOUR: + game_do_command(0, (0 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_0, *((uint16*)&w->var_494), 0); + break; + case WIDX_TRACK_ADDITIONAL_COLOUR: + game_do_command(0, (1 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_0, *((uint16*)&w->var_494), 0); + break; + case WIDX_TRACK_SUPPORT_COLOUR: + game_do_command(0, (4 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_0, *((uint16*)&w->var_494), 0); + break; + case WIDX_MAZE_STYLE_DROPDOWN: + game_do_command(0, (4 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_0, *((uint16*)&w->var_494), 0); + break; + case WIDX_ENTRANCE_STYLE_DROPDOWN: + game_do_command(0, (6 << 8) | 1, 0, (window_ride_entrance_style_list[dropdownIndex] << 8) | w->number, GAME_COMMAND_0, 0, 0); + break; + case WIDX_VEHICLE_COLOUR_SCHEME_DROPDOWN: + game_do_command(0, (5 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_0, 0, 0); + w->var_48C = 0; + break; + case WIDX_VEHICLE_COLOUR_INDEX_DROPDOWN: + w->var_48C = dropdownIndex; + window_invalidate(w); + break; + case WIDX_VEHICLE_MAIN_COLOUR: + game_do_command(0, (2 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_0, w->var_48C, 0); + break; + case WIDX_VEHICLE_ADDITIONAL_COLOUR_1: + game_do_command(0, (3 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_0, w->var_48C, 0); + break; + case WIDX_VEHICLE_ADDITIONAL_COLOUR_2: + game_do_command(0, (7 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_0, w->var_48C, 0); + break; + } +} + +/** + * + * rct2: 0x006B0A8F + */ +static void window_ride_colour_update(rct_window *w) +{ + w->frame_no++; + RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + widget_invalidate(WC_RIDE, w->number, WIDX_TAB_5); + widget_invalidate(WC_RIDE, w->number, WIDX_VEHICLE_PREVIEW); +} + +/** + * + * rct2: 0x006B04EC + */ +static void window_ride_colour_tooldown() +{ + rct_window *w; + short widgetIndex, x, y; + + window_tool_get_registers(w, widgetIndex, x, y); + + if (widgetIndex == WIDX_PAINT_INDIVIDUAL_AREA) + window_ride_set_track_colour_scheme(w, x, y); +} + +/** + * + * rct2: 0x006B04F3 + */ +static void window_ride_colour_tooldrag() +{ + rct_window *w; + short widgetIndex, x, y; + + window_tool_get_registers(w, widgetIndex, x, y); + + if (widgetIndex == WIDX_PAINT_INDIVIDUAL_AREA) + window_ride_set_track_colour_scheme(w, x, y); +} + +/** + * + * rct2: 0x006AFB36 + */ +static void window_ride_colour_invalidate() +{ + rct_window *w; + rct_widget *widgets; + rct_ride_type *rideEntry; + rct_ride *ride; + track_colour trackColour; + vehicle_colour vehicleColour; + int vehicleColourSchemeType; + + window_get_register(w); + + widgets = window_ride_page_widgets[w->page]; + if (w->widgets != widgets) { + w->widgets = widgets; + window_init_scroll_widgets(w); + } + + window_ride_set_pressed_tab(w); + + ride = GET_RIDE(w->number); + rideEntry = ride_get_entry(ride); + + RCT2_GLOBAL(0x013CE952 + 0, uint16) = ride->name; + RCT2_GLOBAL(0x013CE952 + 2, uint32) = ride->name_arguments; + + // Track colours + int colourScheme = *((uint16*)&w->var_494); + trackColour = ride_get_track_colour(ride, colourScheme); + + // Maze style + if (ride->type == RIDE_TYPE_MAZE) { + window_ride_colour_widgets[WIDX_MAZE_STYLE].type = WWT_DROPDOWN; + window_ride_colour_widgets[WIDX_MAZE_STYLE_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + window_ride_colour_widgets[WIDX_MAZE_STYLE].image = STR_BRICK_WALLS + trackColour.supports; + } else { + window_ride_colour_widgets[WIDX_MAZE_STYLE].type = WWT_EMPTY; + window_ride_colour_widgets[WIDX_MAZE_STYLE_DROPDOWN].type = WWT_EMPTY; + } + + // Track, multiple colour schemes + if (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x80000000) { + window_ride_colour_widgets[WIDX_TRACK_COLOUR_SCHEME].type = WWT_DROPDOWN; + window_ride_colour_widgets[WIDX_TRACK_COLOUR_SCHEME_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + window_ride_colour_widgets[WIDX_PAINT_INDIVIDUAL_AREA].type = WWT_FLATBTN; + } else { + window_ride_colour_widgets[WIDX_TRACK_COLOUR_SCHEME].type = WWT_EMPTY; + window_ride_colour_widgets[WIDX_TRACK_COLOUR_SCHEME_DROPDOWN].type = WWT_EMPTY; + window_ride_colour_widgets[WIDX_PAINT_INDIVIDUAL_AREA].type = WWT_EMPTY; + } + + // Track main colour + if (window_ride_has_track_colour(ride, 0)) { + window_ride_colour_widgets[WIDX_TRACK_MAIN_COLOUR].type = WWT_COLORBTN; + window_ride_colour_widgets[WIDX_TRACK_MAIN_COLOUR].image = window_ride_get_colour_button_image(trackColour.main); + } else { + window_ride_colour_widgets[WIDX_TRACK_MAIN_COLOUR].type = WWT_EMPTY; + } + + // Track additional colour + if (window_ride_has_track_colour(ride, 1)) { + window_ride_colour_widgets[WIDX_TRACK_ADDITIONAL_COLOUR].type = WWT_COLORBTN; + window_ride_colour_widgets[WIDX_TRACK_ADDITIONAL_COLOUR].image = window_ride_get_colour_button_image(trackColour.additional); + } else { + window_ride_colour_widgets[WIDX_TRACK_ADDITIONAL_COLOUR].type = WWT_EMPTY; + } + + // Track supports colour + if (window_ride_has_track_colour(ride, 2) && ride->type != RIDE_TYPE_MAZE) { + window_ride_colour_widgets[WIDX_TRACK_SUPPORT_COLOUR].type = WWT_COLORBTN; + window_ride_colour_widgets[WIDX_TRACK_SUPPORT_COLOUR].image = window_ride_get_colour_button_image(trackColour.supports); + } else { + window_ride_colour_widgets[WIDX_TRACK_SUPPORT_COLOUR].type = WWT_EMPTY; + } + + // Track preview + if (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 7) + window_ride_colour_widgets[WIDX_TRACK_PREVIEW].type = WWT_SPINNER; + else + window_ride_colour_widgets[WIDX_TRACK_PREVIEW].type = WWT_EMPTY; + + // Entrance style + if (RCT2_GLOBAL(0x0097D4F2 + (ride->type * 8), uint16) & 0x20) { + window_ride_colour_widgets[WIDX_ENTRANCE_PREVIEW].type = WWT_SPINNER; + window_ride_colour_widgets[WIDX_ENTRANCE_STYLE].type = WWT_DROPDOWN; + window_ride_colour_widgets[WIDX_ENTRANCE_STYLE_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + + window_ride_colour_widgets[WIDX_ENTRANCE_STYLE].image = STR_PLAIN_ENTRANCE + ride->entrance_style; + } else { + window_ride_colour_widgets[WIDX_ENTRANCE_PREVIEW].type = WWT_EMPTY; + window_ride_colour_widgets[WIDX_ENTRANCE_STYLE].type = WWT_EMPTY; + window_ride_colour_widgets[WIDX_ENTRANCE_STYLE_DROPDOWN].type = WWT_EMPTY; + } + + // Vehicle colours + if ( + !(RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x2000) && + (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x4000000) + ) { + vehicleColourSchemeType = ride->colour_scheme_type & 3; + if (vehicleColourSchemeType == 0) + w->var_48C = 0; + + vehicleColour = ride_get_vehicle_colour(ride, w->var_48C); + + window_ride_colour_widgets[WIDX_VEHICLE_PREVIEW].type = WWT_SCROLL; + window_ride_colour_widgets[WIDX_VEHICLE_MAIN_COLOUR].type = WWT_COLORBTN; + window_ride_colour_widgets[WIDX_VEHICLE_MAIN_COLOUR].image = window_ride_get_colour_button_image(vehicleColour.main); + + RCT2_CALLPROC_X(0x006DE4CD, (ride->num_cars_per_train << 8) | ride->subtype, 0, 0, 0, 0, 0, 0); + + uint8 *unk; + uint32 unk_eax = 0; + for (unk = (uint8*)0x00F64E38; *unk != 0xFF; unk++) { + unk_eax |= RCT2_GLOBAL((int)rideEntry + 0x2E + (*unk * 101), uint16); + unk_eax = ror32(unk_eax, 16); + unk_eax |= RCT2_GLOBAL((int)rideEntry + 0x2C + (*unk * 101), uint16); + unk_eax = ror32(unk_eax, 16); + } + + // Additional colours + if (unk_eax & 1) { + window_ride_colour_widgets[WIDX_VEHICLE_ADDITIONAL_COLOUR_1].type = WWT_COLORBTN; + window_ride_colour_widgets[WIDX_VEHICLE_ADDITIONAL_COLOUR_1].image = window_ride_get_colour_button_image(vehicleColour.additional_1); + if (unk_eax & 0x2000000) { + window_ride_colour_widgets[WIDX_VEHICLE_ADDITIONAL_COLOUR_2].type = WWT_COLORBTN; + window_ride_colour_widgets[WIDX_VEHICLE_ADDITIONAL_COLOUR_2].image = window_ride_get_colour_button_image(vehicleColour.additional_2); + } else { + window_ride_colour_widgets[WIDX_VEHICLE_ADDITIONAL_COLOUR_2].type = WWT_EMPTY; + } + } else { + window_ride_colour_widgets[WIDX_VEHICLE_ADDITIONAL_COLOUR_1].type = WWT_EMPTY; + window_ride_colour_widgets[WIDX_VEHICLE_ADDITIONAL_COLOUR_2].type = WWT_EMPTY; + } + + // Vehicle colour scheme type + if ( + !(RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x10000) && + (ride->num_cars_per_train | ride->num_vehicles) > 1 + ) { + window_ride_colour_widgets[WIDX_VEHICLE_COLOUR_SCHEME].type = WWT_DROPDOWN; + window_ride_colour_widgets[WIDX_VEHICLE_COLOUR_SCHEME_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + } else { + window_ride_colour_widgets[WIDX_VEHICLE_COLOUR_SCHEME].type = WWT_EMPTY; + window_ride_colour_widgets[WIDX_VEHICLE_COLOUR_SCHEME_DROPDOWN].type = WWT_EMPTY; + } + RCT2_GLOBAL(0x013CE952 + 6, uint16) = STR_ALL_VEHICLES_IN_SAME_COLOURS + vehicleColourSchemeType; + RCT2_GLOBAL(0x013CE952 + 8, uint16) = RideNameConvention[ride->type].vehicle_name; + RCT2_GLOBAL(0x013CE952 + 10, uint16) = RideNameConvention[ride->type].vehicle_name + 2; + RCT2_GLOBAL(0x013CE952 + 12, uint16) = w->var_48C + 1; + // Vehicle index + if (vehicleColourSchemeType != 0) { + window_ride_colour_widgets[WIDX_VEHICLE_COLOUR_INDEX].type = WWT_DROPDOWN; + window_ride_colour_widgets[WIDX_VEHICLE_COLOUR_INDEX_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + window_ride_colour_widgets[WIDX_VEHICLE_COLOUR_INDEX].image = vehicleColourSchemeType == 1 ? 1134 : 1132; + } else { + window_ride_colour_widgets[WIDX_VEHICLE_COLOUR_INDEX].type = WWT_EMPTY; + window_ride_colour_widgets[WIDX_VEHICLE_COLOUR_INDEX_DROPDOWN].type = WWT_EMPTY; + } + } else { + window_ride_colour_widgets[WIDX_VEHICLE_PREVIEW].type = WWT_EMPTY; + window_ride_colour_widgets[WIDX_VEHICLE_COLOUR_SCHEME].type = WWT_EMPTY; + window_ride_colour_widgets[WIDX_VEHICLE_COLOUR_SCHEME_DROPDOWN].type = WWT_EMPTY; + window_ride_colour_widgets[WIDX_VEHICLE_COLOUR_INDEX].type = WWT_EMPTY; + window_ride_colour_widgets[WIDX_VEHICLE_COLOUR_INDEX_DROPDOWN].type = WWT_EMPTY; + window_ride_colour_widgets[WIDX_VEHICLE_MAIN_COLOUR].type = WWT_EMPTY; + window_ride_colour_widgets[WIDX_VEHICLE_ADDITIONAL_COLOUR_1].type = WWT_EMPTY; + window_ride_colour_widgets[WIDX_VEHICLE_ADDITIONAL_COLOUR_2].type = WWT_EMPTY; + } + + RCT2_GLOBAL(0x013CE960, uint16) = STR_MAIN_COLOUR_SCHEME + colourScheme; + + window_ride_anchor_border_widgets(w); + window_align_tabs(w, WIDX_TAB_1, WIDX_TAB_10); +} + +/** + * + * rct2: 0x006AFF3E + */ +static void window_ride_colour_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi, *clippedDpi; + rct_widget *widget; + rct_ride *ride; + rct_ride_type *rideEntry; + int x, y, spriteIndex, terniaryColour; + track_colour trackColour; + + window_paint_get_registers(w, dpi); + + ride = GET_RIDE(w->number); + rideEntry = ride_get_entry(ride); + + window_draw_widgets(w, dpi); + window_ride_draw_tab_images(dpi, w); + + // Track / shop item preview + widget = &window_ride_colour_widgets[WIDX_TRACK_PREVIEW]; + if (widget->type != WWT_EMPTY) + gfx_fill_rect(dpi, w->x + widget->left + 1, w->y + widget->top + 1, w->x + widget->right - 1, w->y + widget->bottom - 1, 12); + + trackColour = ride_get_track_colour(ride, *((uint16*)&w->var_494)); + + // + if (rideEntry->shop_item == 0xFF) { + x = w->x + widget->left; + y = w->y + widget->top; + + // Track + if (ride->type == RIDE_TYPE_MAZE) { + spriteIndex = 21990 + trackColour.supports; + gfx_draw_sprite(dpi, spriteIndex, x, y, 0); + } else { + spriteIndex = 14222 + (ride->type * 2); + spriteIndex |= (trackColour.additional << 24) | (trackColour.main << 19); + spriteIndex |= 0xA0000000; + gfx_draw_sprite(dpi, spriteIndex, x, y, 0); + + // Supports + spriteIndex = 14222 + (ride->type * 2) + 1; + spriteIndex |= trackColour.supports << 19; + spriteIndex |= 0x20000000; + gfx_draw_sprite(dpi, spriteIndex, x, y, 0); + } + } else { + x = w->x + (widget->left + widget->right) / 2 - 8; + y = w->y + (widget->bottom + widget->top) / 2 - 6; + + uint8 shopItem = rideEntry->shop_item_secondary == 255 ? rideEntry->shop_item : rideEntry->shop_item_secondary; + spriteIndex = 5061 + shopItem; + spriteIndex |= ride->track_colour_main[trackColour.main] << 19; + spriteIndex |= 0x20000000; + + gfx_draw_sprite(dpi, spriteIndex, x, y, 0); + } + + // Entrance preview + trackColour = ride_get_track_colour(ride, 0); + widget = &w->widgets[WIDX_ENTRANCE_PREVIEW]; + if (widget->type != WWT_EMPTY) { + clippedDpi = clip_drawpixelinfo( + dpi, w->x + widget->left + 1, widget->right - widget->left, w->y + widget->top + 1, widget->bottom - widget->top + ); + if (clippedDpi != NULL) { + gfx_clear(clippedDpi, 0x0C0C0C0C); + + terniaryColour = 0; + if (RCT2_GLOBAL(0x00993E1C + (ride->entrance_style * 8), uint32) & 0x40000000) + terniaryColour = 0x40000000 | ((trackColour.main + 112) << 19); + + spriteIndex = (trackColour.additional << 24) | (trackColour.main << 19); + spriteIndex |= 0xA0000000; + spriteIndex += RCT2_GLOBAL(0x00993E7C + (ride->entrance_style * 8), uint32); + + // Back + gfx_draw_sprite(clippedDpi, spriteIndex, 34, 20, terniaryColour); + + // Front + gfx_draw_sprite(clippedDpi, spriteIndex + 4, 34, 20, terniaryColour); + + // ? + if (terniaryColour != 0) + gfx_draw_sprite(clippedDpi, ((spriteIndex + 20) & 0x7FFFF) + terniaryColour, 34, 20, terniaryColour); + } + } +} + +/** + * + * rct2: 0x006B0192 + */ +static void window_ride_colour_scrollpaint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + rct_ride *ride; + rct_ride_type *rideEntry; + rct_widget *vehiclePreviewWidget; + uint8 *unk; + int colour, x, y, spriteIndex; + vehicle_colour vehicleColour; + + window_paint_get_registers(w, dpi); + + ride = GET_RIDE(w->number); + rideEntry = ride_get_entry(ride); + vehiclePreviewWidget = &window_ride_colour_widgets[WIDX_VEHICLE_PREVIEW]; + vehicleColour = ride_get_vehicle_colour(ride, w->var_48C); + + // Background colour + gfx_fill_rect(dpi, dpi->x, dpi->y, dpi->x + dpi->width - 1, dpi->y + dpi->height - 1, 12); + + // ? + x = (vehiclePreviewWidget->right - vehiclePreviewWidget->left) / 2; + y = vehiclePreviewWidget->bottom - vehiclePreviewWidget->top - 15; + RCT2_CALLPROC_X(0x006DE4CD, (ride->num_cars_per_train << 8) | ride->subtype, (int)ride, x, y, (int)w, (int)dpi, 0); + + // ? + colour = (ride->colour_scheme_type & 3) == RIDE_COLOUR_SCHEME_DIFFERENT_PER_CAR ? + w->var_48C : rideEntry->var_013; + colour = RCT2_ADDRESS(0x00F64E38, uint8)[colour]; + unk = (uint8*)rideEntry + (colour * 101); + + y += RCT2_GLOBAL(unk + 0x24, sint8); + + // Draw the coloured spinning vehicle + spriteIndex = RCT2_GLOBAL(unk + 0x2C, uint8) & 0x800 ? w->frame_no / 4 : w->frame_no / 2; + spriteIndex &= RCT2_GLOBAL(unk + 0x1A, uint16); + spriteIndex *= RCT2_GLOBAL(unk + 0x30, uint16); + spriteIndex += RCT2_GLOBAL(unk + 0x32, uint32); + spriteIndex |= (vehicleColour.additional_1 << 24) | (vehicleColour.main << 19); + spriteIndex |= 0x80000000; + gfx_draw_sprite(dpi, spriteIndex, x, y, vehicleColour.additional_2); +} + +#pragma endregion + +#pragma region Music + +const uint8 MusicStyleOrder[] = { + MUSIC_STYLE_GENTLE, + MUSIC_STYLE_SUMMER, + MUSIC_STYLE_WATER, + MUSIC_STYLE_RAGTIME, + MUSIC_STYLE_TECHNO, + MUSIC_STYLE_MECHANICAL, + MUSIC_STYLE_MODERN, + MUSIC_STYLE_WILD_WEST, + MUSIC_STYLE_PIRATES, + MUSIC_STYLE_ROCK, + MUSIC_STYLE_ROCK_STYLE_2, + MUSIC_STYLE_ROCK_STYLE_3, + MUSIC_STYLE_FANTASY, + MUSIC_STYLE_HORROR, + MUSIC_STYLE_TOYLAND, + MUSIC_STYLE_CANDY_STYLE, + MUSIC_STYLE_ROMAN_FANFARE, + MUSIC_STYLE_ORIENTAL, + MUSIC_STYLE_MARTIAN, + MUSIC_STYLE_SPACE, + MUSIC_STYLE_JUNGLE_DRUMS, + MUSIC_STYLE_JURASSIC, + MUSIC_STYLE_EGYPTIAN, + MUSIC_STYLE_DODGEMS_BEAT, + MUSIC_STYLE_SNOW, + MUSIC_STYLE_ICE, + MUSIC_STYLE_MEDIEVAL, + MUSIC_STYLE_URBAN, + MUSIC_STYLE_ORGAN +}; + +static uint8 window_ride_current_music_style_order[42]; + +/** + * + * rct2: 0x006B215D + */ +static void window_ride_toggle_music(rct_window *w) +{ + rct_ride *ride = GET_RIDE(w->number); + + int activateMusic = (ride->lifecycle_flags & RIDE_LIFECYCLE_MUSIC) ? 0 : 1; + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_CANT_CHANGE_OPERATING_MODE; + game_do_command(0, (activateMusic << 8) | 1, 0, (6 << 8) | w->number, GAME_COMMAND_11, 0, 0); +} + +/** + * + * rct2: 0x006B1ED7 + */ +static void window_ride_music_mouseup() +{ + short widgetIndex; + rct_window *w; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + case WIDX_TAB_1: + case WIDX_TAB_2: + case WIDX_TAB_3: + case WIDX_TAB_4: + case WIDX_TAB_5: + case WIDX_TAB_6: + case WIDX_TAB_7: + case WIDX_TAB_8: + case WIDX_TAB_9: + case WIDX_TAB_10: + window_ride_set_page(w, widgetIndex - WIDX_TAB_1); + break; + case WIDX_PLAY_MUSIC: + window_ride_toggle_music(w); + break; + } +} + +/** + * + * rct2: 0x006AF4A2 + */ +static void window_ride_music_resize() +{ + rct_window *w; + + window_get_register(w); + + w->flags |= WF_RESIZABLE; + window_set_resize(w, 316, 81, 316, 81); +} + +/** + * + * rct2: 0x006B1EFC + */ +static void window_ride_music_mousedown(int widgetIndex, rct_window *w, rct_widget *widget) +{ + rct_widget *dropdownWidget; + int i; + + if (widgetIndex != WIDX_MUSIC_DROPDOWN) + return; + + dropdownWidget = widget - 1; + rct_ride *ride = GET_RIDE(w->number); + + int numItems = 0; + if (ride->type == RIDE_TYPE_MERRY_GO_ROUND) { + window_ride_current_music_style_order[numItems++] = MUSIC_STYLE_FAIRGROUND_ORGAN; + } else { + for (i = 0; i < countof(MusicStyleOrder); i++) + window_ride_current_music_style_order[numItems++] = MusicStyleOrder[i]; + + if (RCT2_GLOBAL(0x009AF164, uint32) != 0) + window_ride_current_music_style_order[numItems++] = MUSIC_STYLE_CUSTOM_MUSIC_1; + if (RCT2_GLOBAL(0x009AF16E, uint32) != 0) + window_ride_current_music_style_order[numItems++] = MUSIC_STYLE_CUSTOM_MUSIC_2; + } + + window_dropdown_show_text_custom_width( + w->x + dropdownWidget->left, + w->y + dropdownWidget->top, + dropdownWidget->bottom - dropdownWidget->top + 1, + w->colours[1], + 0, + numItems, + widget->right - dropdownWidget->left + ); + + for (i = 0; i < numItems; i++) { + gDropdownItemsFormat[i] = 1142; + if (window_ride_current_music_style_order[i] == ride->music) + gDropdownItemsChecked = (1 << i); + gDropdownItemsArgs[i] = STR_MUSIC_STYLE_START + window_ride_current_music_style_order[i]; + } +} + +/** + * + * rct2: 0x006B1F03 + */ +static void window_ride_music_dropdown() +{ + rct_window *w; + rct_ride *ride; + uint8 musicStyle; + short widgetIndex, dropdownIndex; + + window_dropdown_get_registers(w, widgetIndex, dropdownIndex); + + if (widgetIndex != WIDX_MUSIC_DROPDOWN || dropdownIndex == -1) + return; + + ride = GET_RIDE(w->number); + musicStyle = window_ride_current_music_style_order[dropdownIndex]; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_CANT_CHANGE_OPERATING_MODE; + game_do_command(0, (musicStyle << 8) | 1, 0, (7 << 8) | w->number, GAME_COMMAND_11, 0, 0); +} + +/** + * + * rct2: 0x006B2198 + */ +static void window_ride_music_update(rct_window *w) +{ + w->frame_no++; + RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + widget_invalidate(WC_RIDE, w->number, WIDX_TAB_6); +} + +/** + * + * rct2: 0x006B1DEA + */ +static void window_ride_music_invalidate() +{ + rct_window *w; + rct_widget *widgets; + int isMusicActivated; + + window_get_register(w); + + widgets = window_ride_page_widgets[w->page]; + if (w->widgets != widgets) { + w->widgets = widgets; + window_init_scroll_widgets(w); + } + + window_ride_set_pressed_tab(w); + + rct_ride *ride = GET_RIDE(w->number); + RCT2_GLOBAL(0x013CE952 + 0, uint16) = ride->name; + RCT2_GLOBAL(0x013CE952 + 2, uint32) = ride->name_arguments; + + // Set selected music + window_ride_music_widgets[WIDX_MUSIC].image = STR_MUSIC_STYLE_START + ride->music; + + // Set music activated + isMusicActivated = ride->lifecycle_flags & (RIDE_LIFECYCLE_MUSIC); + if (isMusicActivated) { + w->pressed_widgets |= (1 << WIDX_PLAY_MUSIC); + w->disabled_widgets &= ~(1 << WIDX_MUSIC); + w->disabled_widgets &= ~(1 << WIDX_MUSIC_DROPDOWN); + } else { + w->pressed_widgets &= ~(1 << WIDX_PLAY_MUSIC); + w->disabled_widgets |= (1 << WIDX_MUSIC); + w->disabled_widgets |= (1 << WIDX_MUSIC_DROPDOWN); + } + + window_ride_anchor_border_widgets(w); + window_align_tabs(w, WIDX_TAB_1, WIDX_TAB_10); +} + +/** + * + * rct2: 0x006B1ECC + */ +static void window_ride_music_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + window_ride_draw_tab_images(dpi, w); +} + +#pragma endregion + +#pragma region Measurements + +/** + * + * rct2: 0x006D3026 + */ +static void window_ride_measurements_design_reset() +{ + RCT2_CALLPROC_EBPSAFE(0x006D3026); +} + +/** + * + * rct2: 0x006D303D + */ +static void window_ride_measurements_design_select_nearby_scenery() +{ + RCT2_CALLPROC_EBPSAFE(0x006D303D); +} + +/** + * + * rct2: 0x006AD4CD + */ +static void window_ride_measurements_design_save(rct_window *w) +{ + RCT2_CALLPROC_X(0x006D2804, 1, 0, 0, 0, (int)w, 0, 0); +} + +/** + * + * rct2: 0x006AD4DA + */ +static void window_ride_measurements_design_cancel() +{ + if (RCT2_GLOBAL(0x009DEA6F, uint8) & 1) + RCT2_CALLPROC_X(0x006D2804, 0, 0, 0, 0, 0, 0, 0); +} + +/** + * + * rct2: 0x006AD4DA + */ +static void window_ride_measurements_close() +{ + window_ride_measurements_design_cancel(); +} + +/** + * + * rct2: 0x006AD478 + */ +static void window_ride_measurements_mouseup() +{ + short widgetIndex; + rct_window *w; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + case WIDX_TAB_1: + case WIDX_TAB_2: + case WIDX_TAB_3: + case WIDX_TAB_4: + case WIDX_TAB_5: + case WIDX_TAB_6: + case WIDX_TAB_7: + case WIDX_TAB_8: + case WIDX_TAB_9: + case WIDX_TAB_10: + window_ride_set_page(w, widgetIndex - WIDX_TAB_1); + break; + case WIDX_SELECT_NEARBY_SCENERY: + window_ride_measurements_design_select_nearby_scenery(); + break; + case WIDX_RESET_SELECTION: + window_ride_measurements_design_reset(); + break; + case WIDX_SAVE_DESIGN: + window_ride_measurements_design_save(w); + break; + case WIDX_CANCEL_DESIGN: + window_ride_measurements_design_cancel(); + break; + } +} + +/** + * + * rct2: 0x006AD564 + */ +static void window_ride_measurements_resize() +{ + rct_window *w; + + window_get_register(w); + + window_set_resize(w, 316, 202, 316, 202); +} + +/** + * + * rct2: 0x006AD4AB + */ +static void window_ride_measurements_mousedown(int widgetIndex, rct_window *w, rct_widget *widget) +{ + if (widgetIndex != WIDX_SAVE_TRACK_DESIGN) + return; + + rct_ride *ride = GET_RIDE(w->number); + + gDropdownItemsFormat[0] = STR_SAVE_TRACK_DESIGN_ITEM; + gDropdownItemsFormat[1] = STR_SAVE_TRACK_DESIGN_WITH_SCENERY_ITEM; + + window_dropdown_show_text( + w->x + widget->left, + w->y + widget->top, + widget->bottom - widget->top + 1, + w->colours[1], + 0, + 2 + ); + RCT2_GLOBAL(0x009DEBA2, sint16) = 0; + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_DESIGNER) + RCT2_GLOBAL(0x009DED34, uint32) |= 2; +} + +/** + * + * rct2: 0x006AD4B2 + */ +static void window_ride_measurements_dropdown() +{ + rct_window *w; + short widgetIndex, dropdownIndex; + + window_dropdown_get_registers(w, widgetIndex, dropdownIndex); + + if (widgetIndex != WIDX_SAVE_TRACK_DESIGN) + return; + + if (dropdownIndex == -1) + dropdownIndex = RCT2_GLOBAL(0x009DEBA2, sint16); + + if (dropdownIndex == 0) + RCT2_CALLPROC_X(0x006D264D, 0, 0, 0, 0, (int)w, 0, 0); + else + RCT2_CALLPROC_X(0x006D27A3, 0, 0, 0, 0, (int)w, 0, 0); +} + +/** + * + * rct2: 0x006AD5DD + */ +static void window_ride_measurements_update(rct_window *w) +{ + w->frame_no++; + RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + widget_invalidate(WC_RIDE, w->number, WIDX_TAB_7); +} + +/** + * + * rct2: 0x006AD4EB + */ +static void window_ride_measurements_tooldown() +{ + rct_window *w; + short x, y, widgetIndex; + + window_tool_get_registers(w, widgetIndex, x, y); + + RCT2_CALLPROC_X(0x006D2AE7, x, y, 0, widgetIndex, (int)w, 0, 0); +} + +/** + * + * rct2: 0x006AD4DA + */ +static void window_ride_measurements_toolabort(rct_window *w) +{ + window_ride_measurements_design_cancel(); +} + +/** + * + * rct2: 0x006ACDBC + */ +static void window_ride_measurements_invalidate() +{ + rct_window *w; + rct_widget *widgets; + + window_get_register(w); + + widgets = window_ride_page_widgets[w->page]; + if (w->widgets != widgets) { + w->widgets = widgets; + window_init_scroll_widgets(w); + } + + window_ride_set_pressed_tab(w); + + rct_ride *ride = GET_RIDE(w->number); + RCT2_GLOBAL(0x013CE952 + 0, uint16) = ride->name; + RCT2_GLOBAL(0x013CE952 + 2, uint32) = ride->name_arguments; + + window_ride_measurements_widgets[WIDX_SAVE_TRACK_DESIGN].tooltip = STR_SAVE_TRACK_DESIGN_NOT_POSSIBLE; + window_ride_measurements_widgets[WIDX_SAVE_TRACK_DESIGN].type = WWT_EMPTY; + if ((RCT2_GLOBAL(0x009DEA6F, uint8) & 1) && RCT2_GLOBAL(0x00F64DE8, uint8) == w->number) { + window_ride_measurements_widgets[WIDX_SELECT_NEARBY_SCENERY].type = WWT_DROPDOWN_BUTTON; + window_ride_measurements_widgets[WIDX_RESET_SELECTION].type = WWT_DROPDOWN_BUTTON; + window_ride_measurements_widgets[WIDX_SAVE_DESIGN].type = WWT_DROPDOWN_BUTTON; + window_ride_measurements_widgets[WIDX_CANCEL_DESIGN].type = WWT_DROPDOWN_BUTTON; + } else { + window_ride_measurements_widgets[WIDX_SELECT_NEARBY_SCENERY].type = WWT_EMPTY; + window_ride_measurements_widgets[WIDX_RESET_SELECTION].type = WWT_EMPTY; + window_ride_measurements_widgets[WIDX_SAVE_DESIGN].type = WWT_EMPTY; + window_ride_measurements_widgets[WIDX_CANCEL_DESIGN].type = WWT_EMPTY; + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_19)) { + if (RCT2_GLOBAL(0x0097CF40 + (ride->type * 8), uint32) & 0x10000000) { + window_ride_measurements_widgets[WIDX_SAVE_TRACK_DESIGN].type = WWT_FLATBTN; + w->disabled_widgets |= (1 << WIDX_SAVE_TRACK_DESIGN); + if (ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED) { + if (ride->excitement != -1) { + w->disabled_widgets &= ~(1 << WIDX_SAVE_TRACK_DESIGN); + window_ride_measurements_widgets[WIDX_SAVE_TRACK_DESIGN].tooltip = STR_SAVE_TRACK_DESIGN; + } + } + } + } + } + + window_ride_anchor_border_widgets(w); + window_align_tabs(w, WIDX_TAB_1, WIDX_TAB_10); +} + +/** + * + * rct2: 0x006ACF07 + */ +static void window_ride_measurements_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + rct_widget *widget; + rct_ride *ride; + rct_string_id stringId; + int x, y, i, numTimes, numLengths; + sint16 holes, maxSpeed, averageSpeed, drops, highestDropHeight, inversions, time; + sint32 maxPositiveVerticalGs, maxNegativeVerticalGs, maxLateralGs, totalAirTime, length; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + window_ride_draw_tab_images(dpi, w); + + if (window_ride_measurements_widgets[WIDX_SAVE_DESIGN].type == WWT_DROPDOWN_BUTTON) { + widget = &window_ride_measurements_widgets[WIDX_PAGE_BACKGROUND]; + + x = w->x + (widget->right - widget->left) / 2; + y = w->y + widget->top + 40; + gfx_draw_string_centred_wrapped(dpi, NULL, x, y, w->width - 8, STR_CLICK_ITEMS_OF_SCENERY_TO_SELECT, 0); + + x = w->x + 4; + y = w->y + window_ride_measurements_widgets[WIDX_SELECT_NEARBY_SCENERY].bottom + 17; + gfx_fill_rect_inset(dpi, x, y, w->x + 312, y + 1, w->colours[1], 0x20); + } else { + ride = GET_RIDE(w->number); + + if (ride->lifecycle_flags & RIDE_LIFECYCLE_19) + gfx_draw_sprite(dpi, 23225, w->x + w->width - 53, w->y + w->height - 73, 0); + + x = w->x + window_ride_measurements_widgets[WIDX_PAGE_BACKGROUND].left + 4; + y = w->y + window_ride_measurements_widgets[WIDX_PAGE_BACKGROUND].top + 4; + + if (ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED) { + // Excitement + RCT2_GLOBAL(0x013CE952 + 0, uint32) = ride->excitement; + RCT2_GLOBAL(0x013CE952 + 4, uint16) = STR_RATING_LOW + min(ride->excitement >> 8, 5); + stringId = ride->excitement == -1 ? STR_EXCITEMENT_RATING_NOT_YET_AVAILABLE : STR_EXCITEMENT_RATING; + gfx_draw_string_left(dpi, stringId, (void*)0x013CE952, 0, x, y); + y += 10; + + // Intensity + RCT2_GLOBAL(0x013CE952 + 0, uint32) = ride->intensity; + RCT2_GLOBAL(0x013CE952 + 4, uint16) = STR_RATING_LOW + min(ride->intensity >> 8, 5); + + stringId = STR_INTENSITY_RATING; + if (ride->excitement == -1) + stringId = STR_INTENSITY_RATING_NOT_YET_AVAILABLE; + else if (ride->intensity >= RIDE_RATING(10,00)) + stringId = STR_INTENSITY_RATING_RED; + + gfx_draw_string_left(dpi, stringId, (void*)0x013CE952, 0, x, y); + y += 10; + + // Nausea + RCT2_GLOBAL(0x013CE952 + 0, uint32) = ride->nausea; + RCT2_GLOBAL(0x013CE952 + 4, uint16) = STR_RATING_LOW + min(ride->nausea >> 8, 5); + stringId = ride->excitement == -1 ? STR_NAUSEA_RATING_NOT_YET_AVAILABLE : STR_NAUSEA_RATING; + gfx_draw_string_left(dpi, stringId, (void*)0x013CE952, 0, x, y); + y += 20; + + // Horizontal rule + gfx_fill_rect_inset(dpi, x, y - 6, x + 303, y - 5, w->colours[1], 0x20); + + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_NO_RAW_STATS)) { + if (ride->type == RIDE_TYPE_MINI_GOLF) { + // Holes + holes = ride->inversions & 0x1F; + gfx_draw_string_left(dpi, STR_HOLES, &holes, 0, x, y); + y += 10; + } else { + // Max speed + maxSpeed = (ride->max_speed * 9) >> 18; + gfx_draw_string_left(dpi, STR_MAX_SPEED, &maxSpeed, 0, x, y); + y += 10; + + // Average speed + averageSpeed = (ride->average_speed * 9) >> 18; + gfx_draw_string_left(dpi, STR_AVERAGE_SPEED, &averageSpeed, 0, x, y); + y += 10; + + // Ride time + numTimes = 0; + for (i = 0; i < ride->num_stations; i++) { + time = ride->time[numTimes]; + if (time != 0) { + RCT2_GLOBAL(0x013CE952 + 0 + (numTimes * 4), uint16) = 1343; + RCT2_GLOBAL(0x013CE952 + 2 + (numTimes * 4), uint16) = time; + numTimes++; + } + } + if (numTimes == 0) { + RCT2_GLOBAL(0x013CE952 + 0, uint16) = 1343; + RCT2_GLOBAL(0x013CE952 + 2, uint16) = 0; + numTimes++; + } + RCT2_GLOBAL(0x013CE94E + (numTimes * 4), uint16) = 1342; + RCT2_GLOBAL(0x013CE952 + 0 + (numTimes * 4), uint16) = 0; + RCT2_GLOBAL(0x013CE952 + 2 + (numTimes * 4), uint16) = 0; + RCT2_GLOBAL(0x013CE952 + 4 + (numTimes * 4), uint16) = 0; + RCT2_GLOBAL(0x013CE952 + 6 + (numTimes * 4), uint16) = 0; + gfx_draw_string_left_clipped(dpi, STR_RIDE_TIME, (void*)0x013CE952, 0, x, y, 308); + y += 10; + } + + // Ride length + numLengths = 0; + for (i = 0; i < ride->num_stations; i++) { + length = ride->length[numLengths]; + if (length != 0) { + length >>= 16; + RCT2_GLOBAL(0x013CE952 + 0 + (numLengths * 4), uint16) = 1346; + RCT2_GLOBAL(0x013CE952 + 2 + (numLengths * 4), uint16) = (length & 0xFFFF); + numLengths++; + } + } + if (numLengths == 0) { + RCT2_GLOBAL(0x013CE952 + 0, uint16) = 1346; + RCT2_GLOBAL(0x013CE952 + 2, uint16) = 0; + numLengths++; + } + RCT2_GLOBAL(0x013CE94E + (numLengths * 4), uint16) = 1345; + RCT2_GLOBAL(0x013CE952 + 0 + (numLengths * 4), uint16) = 0; + RCT2_GLOBAL(0x013CE952 + 2 + (numLengths * 4), uint16) = 0; + RCT2_GLOBAL(0x013CE952 + 4 + (numLengths * 4), uint16) = 0; + RCT2_GLOBAL(0x013CE952 + 6 + (numLengths * 4), uint16) = 0; + gfx_draw_string_left_clipped(dpi, STR_RIDE_LENGTH, (void*)0x013CE952, 0, x, y, 308); + y += 10; + + if (RCT2_GLOBAL(0x0097CF40 + (ride->type * 8), uint32) & 0x80) { + // Max. positive vertical G's + maxPositiveVerticalGs = ride->max_positive_vertical_g; + stringId = maxPositiveVerticalGs >= FIXED_2DP(5,00) ? + STR_MAX_POSITIVE_VERTICAL_G_RED : STR_MAX_POSITIVE_VERTICAL_G; + gfx_draw_string_left(dpi, stringId, &maxPositiveVerticalGs, 0, x, y); + y += 10; + + // Max. negative vertical G's + maxNegativeVerticalGs = ride->max_negative_vertical_g; + stringId = maxNegativeVerticalGs <= -FIXED_2DP(2,00) ? + STR_MAX_NEGATIVE_VERTICAL_G_RED : STR_MAX_NEGATIVE_VERTICAL_G; + gfx_draw_string_left(dpi, stringId, &maxNegativeVerticalGs, 0, x, y); + y += 10; + + // Max lateral G's + maxLateralGs = ride->max_lateral_g; + stringId = maxLateralGs >= FIXED_2DP(2,80) ? + STR_MAX_LATERAL_G_RED : STR_MAX_LATERAL_G; + gfx_draw_string_left(dpi, stringId, &maxLateralGs, 0, x, y); + y += 10; + + // Total 'air' time + totalAirTime = ride->total_air_time * 3; + gfx_draw_string_left(dpi, STR_TOTAL_AIR_TIME, &totalAirTime, 0, x, y); + y += 10; + } + + if (RCT2_GLOBAL(0x0097CF40 + (ride->type * 8), uint32) & 0x400) { + // Drops + drops = ride->drops & 0x3F; + gfx_draw_string_left(dpi, STR_DROPS, &drops, 0, x, y); + y += 10; + + // Highest drop height + highestDropHeight = (ride->highest_drop_height * 3) / 4; + gfx_draw_string_left(dpi, STR_HIGHEST_DROP_HEIGHT, &highestDropHeight, 0, x, y); + y += 10; + } + + if (ride->type != RIDE_TYPE_MINI_GOLF) { + // Inversions + inversions = ride->inversions & 0x1F; + if (inversions != 0) { + gfx_draw_string_left(dpi, STR_INVERSIONS, &inversions, 0, x, y); + y += 10; + } + } + } + } else { + gfx_draw_string_left(dpi, STR_NO_TEST_RESULTS_YET, NULL, 0, x, y); + } + } +} + +#pragma endregion + +#pragma region Graphs + +enum { + GRAPH_VELOCITY, + GRAPH_ALTITUDE, + GRAPH_VERTICAL, + GRAPH_LATERAL +}; + +/** + * + * rct2: 0x006AE8A6 + */ +static void window_ride_set_graph(rct_window *w, int type) +{ + if ((w->list_information_type & 0xFF) == type) { + w->list_information_type ^= 0x8000; + } else { + w->list_information_type &= 0xFF00; + w->list_information_type |= type; + } + window_invalidate(w); +} + +/** + * + * rct2: 0x006AE85D + */ +static void window_ride_graphs_mouseup() +{ + short widgetIndex; + rct_window *w; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + case WIDX_TAB_1: + case WIDX_TAB_2: + case WIDX_TAB_3: + case WIDX_TAB_4: + case WIDX_TAB_5: + case WIDX_TAB_6: + case WIDX_TAB_7: + case WIDX_TAB_8: + case WIDX_TAB_9: + case WIDX_TAB_10: + window_ride_set_page(w, widgetIndex - WIDX_TAB_1); + break; + } +} + +/** + * + * rct2: 0x006AE8DA + */ +static void window_ride_graphs_resize() +{ + rct_window *w; + + window_get_register(w); + + window_set_resize(w, 316, 180, 500, 450); +} + +/** + * + * rct2: 0x006AE878 + */ +static void window_ride_graphs_mousedown(int widgetIndex, rct_window *w, rct_widget *widget) +{ + switch (widgetIndex) { + case WIDX_GRAPH_VELOCITY: + window_ride_set_graph(w, GRAPH_VELOCITY); + break; + case WIDX_GRAPH_ALTITUDE: + window_ride_set_graph(w, GRAPH_ALTITUDE); + break; + case WIDX_GRAPH_VERTICAL: + window_ride_set_graph(w, GRAPH_VERTICAL); + break; + case WIDX_GRAPH_LATERAL: + window_ride_set_graph(w, GRAPH_LATERAL); + break; + } +} + +/** + * + * rct2: 0x006AE95D + */ +static void window_ride_graphs_update(rct_window *w) +{ + rct_widget *widget; + rct_ride_measurement *measurement; + int x; + + w->frame_no++; + RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + widget_invalidate(WC_RIDE, w->number, WIDX_TAB_8); + RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + widget_invalidate(WC_RIDE, w->number, WIDX_GRAPH); + + widget = &window_ride_graphs_widgets[WIDX_GRAPH]; + x = w->scrolls[0].h_left; + if (!(w->list_information_type & 0x8000)) { + measurement = ride_get_measurement(w->number, NULL); + x = measurement == NULL ? + 0 : + measurement->current_item - (((widget->right - widget->left) / 4) * 3); + } + + w->scrolls[0].h_left = clamp(0, x, w->scrolls[0].h_right - ((widget->right - widget->left) - 2)); + widget_scroll_update_thumbs(w, WIDX_GRAPH); +} + +/** + * + * rct2: 0x006AEA75 + */ +static void window_ride_graphs_scrollgetheight() +{ + rct_window *w; + rct_ride_measurement *measurement; + int width, height; + + window_get_register(w); + + RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + + // Set minimum size + width = window_ride_graphs_widgets[WIDX_GRAPH].right - window_ride_graphs_widgets[WIDX_GRAPH].left - 2; + height = 0; + + // Get measurement size + measurement = ride_get_measurement(w->number, NULL); + if (measurement != NULL) + width = max(width, measurement->num_items); + + // Return size + #ifdef _MSC_VER + __asm mov ecx, width + #else + __asm__ ( "mov ecx, 0 " ); + #endif + + #ifdef _MSC_VER + __asm mov edx, height + #else + __asm__ ( "mov edx, %[height] " : [height] "+m" (height) ); + #endif +} + +/** + * + * rct2: 0x006AE953 + */ +static void window_ride_graphs_15() +{ + rct_window *w; + + window_get_register(w); + + w->list_information_type |= 0x8000; +} + +/** + * + * rct2: 0x006AEA05 + */ +static void window_ride_graphs_tooltip() +{ + rct_window *w; + short unused, widgetIndex, result; + rct_ride *ride; + rct_ride_measurement *measurement; + rct_string_id stringId; + + window_dropdown_get_registers(w, unused, widgetIndex); + + result = -1; + if (widgetIndex == WIDX_GRAPH) { + RCT2_GLOBAL(0x013CE952, uint16) = 3158; + measurement = ride_get_measurement(w->number, &stringId); + if (measurement != NULL && (measurement->flags & RIDE_MEASUREMENT_FLAG_RUNNING)) { + RCT2_GLOBAL(0x013CE952 + 4, uint16) = measurement->vehicle_index + 1; + ride = GET_RIDE(w->number); + RCT2_GLOBAL(0x013CE952 + 2, uint16) = RideNameConvention[ride->type].vehicle_name + 6; + result = 0; + } else { + result = stringId; + } + } + + #ifdef _MSC_VER + __asm mov ax, result + #else + __asm__ ( "mov ax, %[result] " : [result] "+m" (result) ); + #endif +} + +/** + * + * rct2: 0x006AE372 + */ +static void window_ride_graphs_invalidate() +{ + rct_window *w; + rct_widget *widgets; + rct_ride *ride; + int x, y; + + window_get_register(w); + + widgets = window_ride_page_widgets[w->page]; + if (w->widgets != widgets) { + w->widgets = widgets; + window_init_scroll_widgets(w); + } + + window_ride_set_pressed_tab(w); + + ride = GET_RIDE(w->number); + + RCT2_GLOBAL(0x013CE952 + 0, uint16) = ride->name; + RCT2_GLOBAL(0x013CE952 + 2, uint32) = ride->name_arguments; + + // Set pressed graph button type + w->pressed_widgets &= ~(1 << WIDX_GRAPH_VELOCITY); + w->pressed_widgets &= ~(1 << WIDX_GRAPH_ALTITUDE); + w->pressed_widgets &= ~(1 << WIDX_GRAPH_VERTICAL); + w->pressed_widgets &= ~(1 << WIDX_GRAPH_LATERAL); + w->pressed_widgets |= (1LL << (WIDX_GRAPH_VELOCITY + (w->list_information_type & 0xFF))); + + // Hide graph buttons that are not applicable + if (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x80) { + window_ride_graphs_widgets[WIDX_GRAPH_VERTICAL].type = WWT_DROPDOWN_BUTTON; + window_ride_graphs_widgets[WIDX_GRAPH_LATERAL].type = WWT_DROPDOWN_BUTTON; + } else { + window_ride_graphs_widgets[WIDX_GRAPH_VERTICAL].type = WWT_EMPTY; + window_ride_graphs_widgets[WIDX_GRAPH_LATERAL].type = WWT_EMPTY; + } + + // Anchor graph widget + x = w->width - 4; + y = w->height - 18; + + window_ride_graphs_widgets[WIDX_GRAPH].right = x; + window_ride_graphs_widgets[WIDX_GRAPH].bottom = y; + y += 3; + window_ride_graphs_widgets[WIDX_GRAPH_VELOCITY].top = y; + window_ride_graphs_widgets[WIDX_GRAPH_ALTITUDE].top = y; + window_ride_graphs_widgets[WIDX_GRAPH_VERTICAL].top = y; + window_ride_graphs_widgets[WIDX_GRAPH_LATERAL].top = y; + y += 11; + window_ride_graphs_widgets[WIDX_GRAPH_VELOCITY].bottom = y; + window_ride_graphs_widgets[WIDX_GRAPH_ALTITUDE].bottom = y; + window_ride_graphs_widgets[WIDX_GRAPH_VERTICAL].bottom = y; + window_ride_graphs_widgets[WIDX_GRAPH_LATERAL].bottom = y; + + window_ride_anchor_border_widgets(w); + window_align_tabs(w, WIDX_TAB_1, WIDX_TAB_10); +} + +/** + * + * rct2: 0x006AE4BC + */ +static void window_ride_graphs_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + window_ride_draw_tab_images(dpi, w); +} + +/** + * + * rct2: 0x006AE4C7 + */ +static void window_ride_graphs_scrollpaint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + rct_ride_measurement *measurement; + rct_widget *widget; + int x, y, width, time, listType, colour, top, bottom, tmp; + rct_string_id stringId; + + window_paint_get_registers(w, dpi); + + gfx_clear(dpi, RCT2_GLOBAL(0x0141FC9D, uint8) * 0x01010101); + + widget = &window_ride_graphs_widgets[WIDX_GRAPH]; + listType = w->list_information_type & 0xFF; + measurement = ride_get_measurement(w->number, &stringId); + if (measurement == NULL) { + // No measurement message + x = (widget->right - widget->left) / 2; + y = (widget->bottom - widget->top) / 2 - 5; + width = widget->right - widget->left - 2; + gfx_draw_string_centred_wrapped(dpi, (void*)0x013CE952, x, y, width, stringId, 0); + return; + } + + // Vertical grid lines + time = 0; + for (x = 0; x < dpi->x + dpi->width; x += 80) { + if (x + 80 >= dpi->x) { + gfx_fill_rect(dpi, x + 0, dpi->y, x + 0, dpi->y + dpi->height - 1, RCT2_GLOBAL(0x0141FCA0, uint8)); + gfx_fill_rect(dpi, x + 16, dpi->y, x + 16, dpi->y + dpi->height - 1, RCT2_GLOBAL(0x0141FC9F, uint8)); + gfx_fill_rect(dpi, x + 32, dpi->y, x + 32, dpi->y + dpi->height - 1, RCT2_GLOBAL(0x0141FC9F, uint8)); + gfx_fill_rect(dpi, x + 48, dpi->y, x + 48, dpi->y + dpi->height - 1, RCT2_GLOBAL(0x0141FC9F, uint8)); + gfx_fill_rect(dpi, x + 64, dpi->y, x + 64, dpi->y + dpi->height - 1, RCT2_GLOBAL(0x0141FC9F, uint8)); + } + time += 5; + } + + // Horizontal grid lines + y = widget->bottom - widget->top - 13; + short yUnit = RCT2_GLOBAL(0x0098DD9A + (listType * 8), uint16); + short ax = RCT2_GLOBAL(0x0098DD9E + (listType * 8), uint16); + short yUnitInterval = RCT2_GLOBAL(0x0098DD9C + (listType * 8), uint16); + short yInterval = RCT2_GLOBAL(0x0098DD98 + (listType * 8), uint16); + + // Scale modifier + if (ax == 1420) { + short unk = RCT2_GLOBAL(0x01359208, uint16); + yUnit -= RCT2_GLOBAL(0x01359208, uint16); + unk *= 2; + yUnit -= unk; + } + + for (y = widget->bottom - widget->top - 13; y >= 8; y -= yInterval, yUnit += yUnitInterval) { + // Minor / major line + colour = yUnit == 0 ? + RCT2_GLOBAL(0x0141FCA0, uint8) : + RCT2_GLOBAL(0x0141FC9F, uint8); + + gfx_fill_rect(dpi, dpi->x, y, dpi->x + dpi->width - 1, y, colour); + + // Scale modifier + if (ax == 1420) + yUnit /= 2; + + gfx_draw_string_left(dpi, ax, &yUnit, 0, w->scrolls[0].h_left + 1, y - 4); + } + + // Time marks + x = 0; + time = 0; + for (x = 0; x < dpi->x + dpi->width; x += 80) { + if (x + 80 >= dpi->x) + gfx_draw_string_left(dpi, 1414, &time, 0, x + 2, 1); + time += 5; + } + + // Plot + x = dpi->x; + for (width = 0; width < dpi->width; width++, x++) { + if (x < 0 || x >= measurement->num_items - 1) + continue; + + switch (listType) { + case GRAPH_VELOCITY: + top = measurement->velocity[x] / 2; + bottom = measurement->velocity[x + 1] / 2; + break; + case GRAPH_ALTITUDE: + top = measurement->altitude[x]; + bottom = measurement->altitude[x + 1]; + break; + case GRAPH_VERTICAL: + top = measurement->vertical[x] + 39; + bottom = measurement->vertical[x + 1] + 39; + break; + case GRAPH_LATERAL: + top = measurement->lateral[x] + 52; + bottom = measurement->lateral[x + 1] + 52; + break; + } + + top = widget->bottom - widget->top - top - 13; + bottom = widget->bottom - widget->top - bottom - 13; + if (top > bottom) { + tmp = top; + top = bottom; + bottom = tmp; + } + gfx_fill_rect(dpi, x, top, x, bottom, x > measurement->current_item ? 17 : 21); + } +} + +#pragma endregion + +#pragma region Income + +/** + * + * rct2: 0x006ADEFD + */ +static void window_ride_income_toggle_primary_price(rct_window *w) +{ + RCT2_CALLPROC_X(0x006ADEFD, 0, 0, 0, 0, (int)w, 0, 0); +} + +/** + * + * rct2: 0x006AE06E + */ +static void window_ride_income_toggle_secondary_price(rct_window *w) +{ + RCT2_CALLPROC_X(0x006AE06E, 0, 0, 0, 0, (int)w, 0, 0); +} + +/** + * + * rct2: 0x006AE1E4 + */ +static void window_ride_income_increase_primary_price(rct_window *w) +{ + RCT2_CALLPROC_X(0x006AE1E4, 0, 0, 0, 0, (int)w, 0, 0); +} + +/** + * + * rct2: 0x006AE237 + */ +static void window_ride_income_decrease_primary_price(rct_window *w) +{ + RCT2_CALLPROC_X(0x006AE237, 0, 0, 0, 0, (int)w, 0, 0); +} + +/** + * + * rct2: 0x006AE269 + */ +static void window_ride_income_increase_secondary_price(rct_window *w) +{ + RCT2_CALLPROC_X(0x006AE269, 0, 0, 0, 0, (int)w, 0, 0); +} + +/** + * + * rct2: 0x006AE28D + */ +static void window_ride_income_decrease_secondary_price(rct_window *w) +{ + RCT2_CALLPROC_X(0x006AE28D, 0, 0, 0, 0, (int)w, 0, 0); +} + +/** + * + * rct2: 0x006ADEA9 + */ +static void window_ride_income_mouseup() +{ + short widgetIndex; + rct_window *w; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + case WIDX_TAB_1: + case WIDX_TAB_2: + case WIDX_TAB_3: + case WIDX_TAB_4: + case WIDX_TAB_5: + case WIDX_TAB_6: + case WIDX_TAB_7: + case WIDX_TAB_8: + case WIDX_TAB_9: + case WIDX_TAB_10: + window_ride_set_page(w, widgetIndex - WIDX_TAB_1); + break; + case WIDX_PRIMARY_PRICE_SAME_THROUGHOUT_PARK: + window_ride_income_toggle_primary_price(w); + break; + case WIDX_SECONDARY_PRICE_SAME_THROUGHOUT_PARK: + window_ride_income_toggle_secondary_price(w); + break; + } +} + +/** + * + * rct2: 0x006AE2F8 + */ +static void window_ride_income_resize() +{ + rct_window *w; + + window_get_register(w); + + window_set_resize(w, 316, 177, 316, 177); +} + +/** + * + * rct2: 0x006ADED4 + */ +static void window_ride_income_mousedown(int widgetIndex, rct_window *w, rct_widget *widget) +{ + switch (widgetIndex) { + case WIDX_PRIMARY_PRICE_INCREASE: + window_ride_income_increase_primary_price(w); + break; + case WIDX_PRIMARY_PRICE_DECREASE: + window_ride_income_decrease_primary_price(w); + break; + case WIDX_SECONDARY_PRICE_INCREASE: + window_ride_income_increase_secondary_price(w); + break; + case WIDX_SECONDARY_PRICE_DECREASE: + window_ride_income_decrease_secondary_price(w); + break; + } +} + +/** + * + * rct2: 0x006AE2BF + */ +static void window_ride_income_update(rct_window *w) +{ + rct_ride *ride; + + w->frame_no++; + RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + widget_invalidate(WC_RIDE, w->number, WIDX_TAB_9); + + ride = GET_RIDE(w->number); + if (ride->var_14D & 2) { + ride->var_14D &= ~2; + window_invalidate(w); + } +} + +/** + * + * rct2: 0x006ADAA3 + */ +static void window_ride_income_invalidate() +{ + rct_window *w; + rct_widget *widgets; + rct_ride_type *rideEntry; + rct_string_id stringId; + int primaryItem, secondaryItem; + + window_get_register(w); + + widgets = window_ride_page_widgets[w->page]; + if (w->widgets != widgets) { + w->widgets = widgets; + window_init_scroll_widgets(w); + } + + window_ride_set_pressed_tab(w); + + rct_ride *ride = GET_RIDE(w->number); + RCT2_GLOBAL(0x013CE952 + 0, uint16) = ride->name; + RCT2_GLOBAL(0x013CE952 + 2, uint32) = ride->name_arguments; + + rideEntry = ride_get_entry(ride); + + // Primary item + w->pressed_widgets &= ~(1 << WIDX_PRIMARY_PRICE_SAME_THROUGHOUT_PARK); + w->disabled_widgets &= ~(1 << WIDX_PRIMARY_PRICE); + if ( + !(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_FREE_ENTRY) && + rideEntry->shop_item == 255 && + ride->type != RIDE_TYPE_BATHROOM + ) { + w->disabled_widgets |= (1 << WIDX_PRIMARY_PRICE); + } + + window_ride_income_widgets[WIDX_PRIMARY_PRICE_LABEL].image = STR_RIDE_INCOME_ADMISSION_PRICE; + window_ride_income_widgets[WIDX_SECONDARY_PRICE_LABEL].image = STR_ON_RIDE_PHOTO_PRICE; + window_ride_income_widgets[WIDX_PRIMARY_PRICE_SAME_THROUGHOUT_PARK].type = WWT_EMPTY; + + window_ride_income_widgets[WIDX_PRIMARY_PRICE].image = 1429; + RCT2_GLOBAL(0x013CE952 + 6, money32) = ride->price; + if (ride->price == 0) + window_ride_income_widgets[WIDX_PRIMARY_PRICE].image = STR_FREE; + + primaryItem = 31; + if (ride->type != RIDE_TYPE_BATHROOM) { + if ((primaryItem = (sint8)rideEntry->shop_item) != -1) { + window_ride_income_widgets[WIDX_PRIMARY_PRICE_SAME_THROUGHOUT_PARK].type = WWT_CHECKBOX; + if (primaryItem < 32) { + if (RCT2_GLOBAL(0x01358838, uint32) & (1 << primaryItem)) + w->pressed_widgets |= (1 << WIDX_PRIMARY_PRICE_SAME_THROUGHOUT_PARK); + + if (primaryItem != 31) + window_ride_income_widgets[WIDX_PRIMARY_PRICE_LABEL].image = 1960 + primaryItem; + } else { + primaryItem -= 32; + if (RCT2_GLOBAL(0x0135934C, uint32) & (1 << primaryItem)) + w->pressed_widgets |= (1 << WIDX_PRIMARY_PRICE_SAME_THROUGHOUT_PARK); + + window_ride_income_widgets[WIDX_PRIMARY_PRICE_LABEL].image = 2100 + primaryItem; + } + } + } + + // Get secondary item + secondaryItem = RCT2_GLOBAL(0x0097D7CB + (ride->type * 4), uint8); + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_ON_RIDE_PHOTO)) { + if ((secondaryItem = (sint8)rideEntry->shop_item_secondary) != -1) { + // Set secondary item label + stringId = 1960 + secondaryItem; + if (stringId >= 1992) + stringId += 108; + + window_ride_income_widgets[WIDX_SECONDARY_PRICE_LABEL].image = stringId; + } + } + + if (secondaryItem == -1) { + // Hide secondary item widgets + window_ride_income_widgets[WIDX_SECONDARY_PRICE_LABEL].type = WWT_EMPTY; + window_ride_income_widgets[WIDX_SECONDARY_PRICE].type = WWT_EMPTY; + window_ride_income_widgets[WIDX_SECONDARY_PRICE_INCREASE].type = WWT_EMPTY; + window_ride_income_widgets[WIDX_SECONDARY_PRICE_DECREASE].type = WWT_EMPTY; + window_ride_income_widgets[WIDX_SECONDARY_PRICE_SAME_THROUGHOUT_PARK].type = WWT_EMPTY; + } else { + // Set same price throughout park checkbox + w->pressed_widgets &= ~(1 << WIDX_SECONDARY_PRICE_SAME_THROUGHOUT_PARK); + if (secondaryItem < 32) { + if (RCT2_GLOBAL(0x01358838, uint32) & (1 << secondaryItem)) + w->pressed_widgets |= (1 << WIDX_SECONDARY_PRICE_SAME_THROUGHOUT_PARK); + } else { + secondaryItem -= 32; + if (RCT2_GLOBAL(0x0135884C, uint32) & (1 << secondaryItem)) + w->pressed_widgets |= (1 << WIDX_SECONDARY_PRICE_SAME_THROUGHOUT_PARK); + } + + // Show widgets + window_ride_income_widgets[WIDX_SECONDARY_PRICE_LABEL].type = WWT_24; + window_ride_income_widgets[WIDX_SECONDARY_PRICE].type = WWT_SPINNER; + window_ride_income_widgets[WIDX_SECONDARY_PRICE_INCREASE].type = WWT_DROPDOWN_BUTTON; + window_ride_income_widgets[WIDX_SECONDARY_PRICE_DECREASE].type = WWT_DROPDOWN_BUTTON; + window_ride_income_widgets[WIDX_SECONDARY_PRICE_SAME_THROUGHOUT_PARK].type = WWT_CHECKBOX; + + // Set secondary item price + window_ride_income_widgets[WIDX_SECONDARY_PRICE].image = 1799; + RCT2_GLOBAL(0x013CE952 + 10, money32) = ride->price_secondary; + if (ride->price_secondary == 0) + window_ride_income_widgets[WIDX_SECONDARY_PRICE].image = STR_FREE; + } + + window_ride_anchor_border_widgets(w); + window_align_tabs(w, WIDX_TAB_1, WIDX_TAB_10); +} + +/** + * + * rct2: 0x006ADCE5 + */ +static void window_ride_income_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + rct_ride *ride; + rct_ride_type *rideEntry; + rct_string_id stringId; + money32 profit, costPerHour; + int x, y, primaryItem, secondaryItem; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + window_ride_draw_tab_images(dpi, w); + + ride = GET_RIDE(w->number); + rideEntry = ride_get_entry(ride); + + x = w->x + window_ride_income_widgets[WIDX_PAGE_BACKGROUND].left + 4; + y = w->y + window_ride_income_widgets[WIDX_PAGE_BACKGROUND].top + 29; + + // Primary item profit / loss per item sold + primaryItem = (sint8)rideEntry->shop_item; + if (primaryItem != -1) { + profit = ride->price; + + stringId = STR_PROFIT_PER_ITEM_SOLD; + profit -= primaryItem < 32 ? + RCT2_GLOBAL(0x00982164 + (primaryItem * 8), uint16) : + RCT2_GLOBAL(0x00982144 + (primaryItem * 8), uint16); + if (profit < 0) { + profit *= -1; + stringId = STR_LOSS_PER_ITEM_SOLD; + } + + gfx_draw_string_left(dpi, stringId, &profit, 0, x, y); + } + y += 39; + + // Secondary item profit / loss per item sold + secondaryItem = RCT2_GLOBAL(0x0097D7CB + (ride->type * 4), uint8); + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_ON_RIDE_PHOTO)) + secondaryItem = (sint8)rideEntry->shop_item_secondary; + + if (secondaryItem != -1) { + profit = ride->price_secondary; + + stringId = STR_PROFIT_PER_ITEM_SOLD; + profit -= primaryItem < 32 ? + RCT2_GLOBAL(0x00982164 + (primaryItem * 8), uint16) : + RCT2_GLOBAL(0x00982144 + (primaryItem * 8), uint16); + if (profit < 0) { + profit *= -1; + stringId = STR_LOSS_PER_ITEM_SOLD; + } + + gfx_draw_string_left(dpi, stringId, &profit, 0, x, y); + } + y += 15; + + // Income per hour + if (ride->income_per_hour != MONEY32_UNDEFINED) { + gfx_draw_string_left(dpi, STR_INCOME_PER_HOUR, &ride->income_per_hour, 0, x, y); + y += 10; + } + + // Running cost per hour + costPerHour = ride->upkeep_cost * 16; + stringId = ride->upkeep_cost == 0xFFFF ? STR_RUNNING_COST_UNKNOWN : STR_RUNNING_COST_PER_HOUR; + gfx_draw_string_left(dpi, stringId, &costPerHour, 0, x, y); + y += 10; + + // Profit per hour + if (ride->profit != MONEY32_UNDEFINED) { + gfx_draw_string_left(dpi, STR_PROFIT_PER_HOUR, &ride->profit, 0, x, y); + y += 10; + } + y += 5; + + // Total profit + gfx_draw_string_left(dpi, STR_TOTAL_PROFIT, &ride->total_profit, 0, x, y); +} + +#pragma endregion + +#pragma region Customer + +/** + * + * rct2: 0x006AD986 + */ +static void window_ride_customer_mouseup() +{ + short widgetIndex; + rct_window *w; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + case WIDX_TAB_1: + case WIDX_TAB_2: + case WIDX_TAB_3: + case WIDX_TAB_4: + case WIDX_TAB_5: + case WIDX_TAB_6: + case WIDX_TAB_7: + case WIDX_TAB_8: + case WIDX_TAB_9: + case WIDX_TAB_10: + window_ride_set_page(w, widgetIndex - WIDX_TAB_1); + break; + case WIDX_SHOW_GUESTS_THOUGHTS: + RCT2_CALLPROC_X(0x006993BA, 2, w->number, 0, 0, 0, 0, 0); + break; + case WIDX_SHOW_GUESTS_ON_RIDE: + RCT2_CALLPROC_X(0x006993BA, 0, w->number, 0, 0, 0, 0, 0); + break; + case WIDX_SHOW_GUESTS_QUEUING: + RCT2_CALLPROC_X(0x006993BA, 1, w->number, 0, 0, 0, 0, 0); + break; + } +} + +/** + * + * rct2: 0x006ADA29 + */ +static void window_ride_customer_resize() +{ + rct_window *w; + + window_get_register(w); + + w->flags |= WF_RESIZABLE; + window_set_resize(w, 316, 139, 316, 139); +} + +/** + * + * rct2: 0x006AD9DD + */ +static void window_ride_customer_update(rct_window *w) +{ + rct_ride *ride; + + w->var_492++; + if (w->var_492 >= 24) + w->var_492 = 0; + + RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + widget_invalidate(WC_RIDE, w->number, WIDX_TAB_10); + + ride = GET_RIDE(w->number); + if (ride->var_14D & 1) { + ride->var_14D &= ~1; + window_invalidate(w); + } +} + +/** + * + * rct2: 0x006AD5F8 + */ +static void window_ride_customer_invalidate() +{ + rct_window *w; + rct_widget *widgets; + + window_get_register(w); + + widgets = window_ride_page_widgets[w->page]; + if (w->widgets != widgets) { + w->widgets = widgets; + window_init_scroll_widgets(w); + } + + window_ride_set_pressed_tab(w); + + rct_ride *ride = GET_RIDE(w->number); + RCT2_GLOBAL(0x013CE952 + 0, uint16) = ride->name; + RCT2_GLOBAL(0x013CE952 + 2, uint32) = ride->name_arguments; + + if (RCT2_GLOBAL(0x0097CF40 + (ride->type * 8), uint32) * 0x20000) { + window_ride_customer_widgets[WIDX_SHOW_GUESTS_THOUGHTS].type = WWT_FLATBTN; + window_ride_customer_widgets[WIDX_SHOW_GUESTS_ON_RIDE].type = WWT_FLATBTN; + window_ride_customer_widgets[WIDX_SHOW_GUESTS_QUEUING].type = WWT_FLATBTN; + } else { + window_ride_customer_widgets[WIDX_SHOW_GUESTS_ON_RIDE].type = WWT_EMPTY; + window_ride_customer_widgets[WIDX_SHOW_GUESTS_QUEUING].type = WWT_EMPTY; + } + + window_ride_anchor_border_widgets(w); + window_align_tabs(w, WIDX_TAB_1, WIDX_TAB_10); +} + +/** + * + * rct2: 0x006AD6CD + */ +static void window_ride_customer_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + rct_ride *ride; + int x, y; + uint8 shopItem; + sint16 popularity, satisfaction, queueTime, age; + sint32 customersPerHour; + rct_string_id stringId; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + window_ride_draw_tab_images(dpi, w); + + ride = GET_RIDE(w->number); + x = w->x + window_ride_customer_widgets[WIDX_PAGE_BACKGROUND].left + 4; + y = w->y + window_ride_customer_widgets[WIDX_PAGE_BACKGROUND].top + 4; + + // Customers per hour + customersPerHour = ride->var_124 + ride->var_126 + ride->var_128 + ride->var_12A + ride->var_12C + + ride->var_12E + ride->age + ride->running_cost + ride->var_134 + ride->var_136; + customersPerHour *= 12; + gfx_draw_string_left(dpi, STR_CUSTOMERS_PER_HOUR, &customersPerHour, 0, x, y); + y += 10; + + // Popularity + popularity = ride->var_158 & 0xFF; + if (popularity == 255) { + stringId = STR_POPULARITY_UNKNOWN; + } else { + stringId = STR_POPULARITY_PERCENT; + popularity *= 4; + } + gfx_draw_string_left(dpi, stringId, &popularity, 0, x, y); + y += 10; + + // Satisfaction + satisfaction = ride->var_14A & 0xFF; + if (satisfaction == 255) { + stringId = STR_SATISFACTION_UNKNOWN; + } else { + stringId = STR_SATISFACTION_PERCENT; + satisfaction *= 5; + } + gfx_draw_string_left(dpi, stringId, &satisfaction, 0, x, y); + y += 10; + + // Queue time + queueTime = ride_get_max_queue_time(ride); + stringId = queueTime == 1 ? STR_QUEUE_TIME_MINUTE : STR_QUEUE_TIME_MINUTES; + y += gfx_draw_string_left_wrapped(dpi, &queueTime, x, y, 308, stringId, 0); + y += 5; + + // Primary shop items sold + shopItem = ride_get_entry(ride)->shop_item; + if (shopItem != 0xFF) { + stringId = 2016 + shopItem; + if (stringId >= 2048) + stringId += 96; + + RCT2_GLOBAL(0x013CE952 + 0, uint16) = stringId; + RCT2_GLOBAL(0x013CE952 + 2, uint32) = ride->var_1A4; + gfx_draw_string_left(dpi, STR_ITEMS_SOLD, (void*)0x013CE952, 0, x, y); + y += 10; + } + + // Secondary shop items sold / on-ride photos sold + shopItem = ride->lifecycle_flags & RIDE_LIFECYCLE_ON_RIDE_PHOTO ? + RCT2_GLOBAL(0x0097D7CB + (ride->type * 4), uint8) : + ride_get_entry(ride)->shop_item_secondary; + if (shopItem != 0xFF) { + stringId = 2016 + shopItem; + if (stringId >= 2048) + stringId += 96; + + RCT2_GLOBAL(0x013CE952 + 0, uint16) = stringId; + RCT2_GLOBAL(0x013CE952 + 2, uint32) = ride->var_1A4; + gfx_draw_string_left(dpi, STR_ITEMS_SOLD, (void*)0x013CE952, 0, x, y); + y += 10; + } + + // Total customers + gfx_draw_string_left(dpi, STR_TOTAL_CUSTOMERS, &ride->total_customers, 0, x, y); + y += 10; + + // Guests favourite + if (gRideClassifications[ride->type] == RIDE_CLASS_RIDE) { + stringId = ride->guests_favourite == 1 ? + STR_FAVOURITE_RIDE_OF_GUEST : + STR_FAVOURITE_RIDE_OF_GUESTS; + gfx_draw_string_left(dpi, stringId, &ride->guests_favourite, 0, x, y); + y += 10; + } + y += 2; + + // Age + age = (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, uint16) - ride->build_date) / 8; + stringId = age == 0 ? + STR_BUILT_THIS_YEAR : + age == 1 ? + STR_BUILT_LAST_YEAR : + STR_BUILT_YEARS_AGO; + gfx_draw_string_left(dpi, stringId, &age, 0, x, y); +} + +#pragma endregion \ No newline at end of file diff --git a/src/window_ride_list.c b/src/windows/ride_list.c similarity index 93% rename from src/window_ride_list.c rename to src/windows/ride_list.c index 0298a93c9e..69704cfd6a 100644 --- a/src/window_ride_list.c +++ b/src/windows/ride_list.c @@ -19,15 +19,15 @@ *****************************************************************************/ #include -#include "addresses.h" -#include "game.h" -#include "ride.h" -#include "string_ids.h" -#include "sprite.h" -#include "sprites.h" -#include "widget.h" -#include "window.h" -#include "window_dropdown.h" +#include "../addresses.h" +#include "../game.h" +#include "../ride/ride.h" +#include "../localisation/localisation.h" +#include "../world/sprite.h" +#include "../sprites.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "dropdown.h" enum { PAGE_RIDES, @@ -432,52 +432,6 @@ static void window_ride_list_paint() window_ride_list_draw_tab_images(dpi, w); } -/** - * - * rct2: 0x006AF561 - */ -static void ride_get_status(int rideIndex, int *formatSecondary, int *argument) -{ - rct_ride *ride = &g_ride_list[rideIndex]; - - if (ride->lifecycle_flags & RIDE_LIFECYCLE_CRASHED) { - *formatSecondary = STR_CRASHED; - return; - } - if (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN) { - *formatSecondary = STR_BROKEN_DOWN; - return; - } - if (ride->status == RIDE_STATUS_CLOSED) { - *formatSecondary = STR_CLOSED; - return; - } - if (ride->status == RIDE_STATUS_TESTING) { - *formatSecondary = STR_TEST_RUN; - return; - } - rct_peep *peep = GET_PEEP(ride->race_winner); - if (ride->mode == RIDE_MODE_RACE && !(ride->lifecycle_flags & RIDE_LIFECYCLE_PASS_STATION_NO_STOPPING) && ride->race_winner != 0xFFFF && peep->sprite_identifier == SPRITE_IDENTIFIER_PEEP) { - if (peep->name_string_idx == STR_GUEST) { - *argument = peep->id; - *formatSecondary = STR_RACE_WON_BY_GUEST; - } else { - *argument = peep->name_string_idx; - *formatSecondary = STR_RACE_WON_BY; - } - } else { - if (!(RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + ride->type * 8, uint32) & 0x20000)) { - *argument = ride->num_riders; - *formatSecondary = STR_PERSON_ON_RIDE; - if(*argument != 1) - *formatSecondary = STR_PEOPLE_ON_RIDE; - - } else { - *formatSecondary = STR_OPEN; - } - } -} - /** * * rct2: 0x006B3240 diff --git a/src/window_save_prompt.c b/src/windows/save_prompt.c similarity index 87% rename from src/window_save_prompt.c rename to src/windows/save_prompt.c index 5ab0081bb5..1c8dc75980 100644 --- a/src/window_save_prompt.c +++ b/src/windows/save_prompt.c @@ -18,16 +18,15 @@ * along with this program. If not, see . *****************************************************************************/ -#include "addresses.h" -#include "game.h" -#include "rct2.h" -#include "string_ids.h" -#include "sprites.h" -#include "tutorial.h" -#include "widget.h" -#include "window.h" -#include "audio.h" -#include "config.h" +#include "../addresses.h" +#include "../audio/audio.h" +#include "../game.h" +#include "../localisation/localisation.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../sprites.h" +#include "../config.h" +#include "../tutorial.h" enum WINDOW_SAVE_PROMPT_WIDGET_IDX { WIDX_BACKGROUND, @@ -125,46 +124,48 @@ void window_save_prompt_open() // Check if window is already open window = window_bring_to_front_by_id(WC_SAVE_PROMPT, 0); - if (window == NULL) { - if (prompt_mode == PM_QUIT) { - widgets = window_quit_prompt_widgets; - enabled_widgets = - (1 << WQIDX_CLOSE) | - (1 << WQIDX_OK) | - (1 << WQIDX_CANCEL); - x = 177; - y = 34; - } else { - widgets = window_save_prompt_widgets; - enabled_widgets = - (1 << WIDX_CLOSE) | - (1 << WIDX_SAVE) | - (1 << WIDX_DONT_SAVE) | - (1 << WIDX_CANCEL); - x = 260; - y = 50; - } + if (window){ + window_close(window); + } - window = window_create( - (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) / 2) - x/2, - max(28, (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16) / 2) - y/2), + if (prompt_mode == PM_QUIT) { + widgets = window_quit_prompt_widgets; + enabled_widgets = + (1 << WQIDX_CLOSE) | + (1 << WQIDX_OK) | + (1 << WQIDX_CANCEL); + x = 177; + y = 34; + } else { + widgets = window_save_prompt_widgets; + enabled_widgets = + (1 << WIDX_CLOSE) | + (1 << WIDX_SAVE) | + (1 << WIDX_DONT_SAVE) | + (1 << WIDX_CANCEL); + x = 260; + y = 50; + } + + window = window_create( + (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) / 2) - x / 2, + max(28, (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16) / 2) - y / 2), x, y, (uint32*)window_save_prompt_events, WC_SAVE_PROMPT, WF_TRANSPARENT | WF_STICK_TO_FRONT - ); + ); - window->widgets = widgets; - window->enabled_widgets = enabled_widgets; - window_init_scroll_widgets(window); - window->colours[0] = 154; + window->widgets = widgets; + window->enabled_widgets = enabled_widgets; + window_init_scroll_widgets(window); + window->colours[0] = 154; - // Pause the game - RCT2_GLOBAL(0x009DEA6E, uint8) |= 2; - pause_sounds(); - window_invalidate_by_id(0x80 | WC_TOP_TOOLBAR, 0); - } + // Pause the game + RCT2_GLOBAL(0x009DEA6E, uint8) |= 2; + pause_sounds(); + window_invalidate_by_id(0x80 | WC_TOP_TOOLBAR, 0); stringId = prompt_mode + STR_LOAD_GAME; if (stringId == STR_LOAD_GAME && RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 2) diff --git a/src/window_scenery.c b/src/windows/scenery.c similarity index 96% rename from src/window_scenery.c rename to src/windows/scenery.c index 86d3cbcdd8..253fc9284b 100644 --- a/src/window_scenery.c +++ b/src/windows/scenery.c @@ -20,19 +20,20 @@ #include #include -#include "addresses.h" -#include "audio.h" -#include "game.h" -#include "map.h" -#include "gfx.h" -#include "peep.h" -#include "sprite.h" +#include "../addresses.h" +#include "../audio/audio.h" +#include "../drawing/drawing.h" +#include "../game.h" +#include "../interface/viewport.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../localisation/localisation.h" +#include "../peep/peep.h" +#include "../world/map.h" +#include "../world/scenery.h" +#include "../world/sprite.h" +#include "dropdown.h" #include "scenery.h" -#include "string_ids.h" -#include "viewport.h" -#include "widget.h" -#include "window.h" -#include "window_scenery.h" enum { WINDOW_SCENERY_TAB_1, @@ -580,20 +581,15 @@ static void window_scenery_resize() * rct2: 0x006E1A25 */ static void window_scenery_mousedown(int widgetIndex, rct_window* w, rct_widget* widget) { - int eax; - switch (widgetIndex) { case WIDX_SCENERY_PRIMARY_COLOUR_BUTTON: - eax = (window_scenery_primary_colour << 8) + 0x80 + w->colours[1]; - RCT2_CALLPROC_X(0x006ED43D, eax, 0, 0, widgetIndex, (int)w, (int)widget, 0xFFFFFFFF); + window_dropdown_show_colour(w, widget, w->colours[1], window_scenery_primary_colour); break; case WIDX_SCENERY_SECONDARY_COLOUR_BUTTON: - eax = (window_scenery_secondary_colour << 8) + 0x80 + w->colours[1]; - RCT2_CALLPROC_X(0x006ED43D, eax, 0, 0, widgetIndex, (int)w, (int)widget, 0xFFFFFFFF); + window_dropdown_show_colour(w, widget, w->colours[1], window_scenery_secondary_colour); break; case WIDX_SCENERY_TERTIARY_COLOUR_BUTTON: - eax = (window_scenery_tertiary_colour << 8) + 0x80 + w->colours[1]; - RCT2_CALLPROC_X(0x006ED43D, eax, 0, 0, widgetIndex, (int)w, (int)widget, 0xFFFFFFFF); + window_dropdown_show_colour(w, widget, w->colours[1], window_scenery_tertiary_colour); break; } @@ -706,15 +702,15 @@ static void window_scenery_update(rct_window *w) sint16 tabSelectedSceneryId = window_scenery_selected_scenery_by_tab[tabIndex]; if (tabSelectedSceneryId != -1) { - if (tabSelectedSceneryId > 0x400) { // banner + if (tabSelectedSceneryId >= 0x400) { // banner RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TOOL, uint8) = 0x18; - } else if (tabSelectedSceneryId > 0x300) { // large scenery + } else if (tabSelectedSceneryId >= 0x300) { // large scenery RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TOOL, uint8) = g_largeSceneryEntries[tabSelectedSceneryId - 0x300]->large_scenery.tool_id; - } else if (tabSelectedSceneryId > 0x200) { // wall + } else if (tabSelectedSceneryId >= 0x200) { // wall RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TOOL, uint8) = g_wallSceneryEntries[tabSelectedSceneryId - 0x200]->wall.tool_id; - } else if (tabSelectedSceneryId > 0x100) { // path bit + } else if (tabSelectedSceneryId >= 0x100) { // path bit RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TOOL, uint8) = g_pathBitSceneryEntries[tabSelectedSceneryId - 0x100]->path_bit.tool_id; } else { // small scenery @@ -774,7 +770,7 @@ void window_scenery_scrollmousedown() { window_scenery_selected_scenery_by_tab[tabIndex] = sceneryId; window_scenery_is_repaint_scenery_tool_on &= 0xFE; - sound_play_panned(4, (w->width >> 1) + w->x); + sound_play_panned(4, (w->width >> 1) + w->x, 0, 0, 0); w->scenery.hover_counter = -16; RCT2_GLOBAL(0x00F64EB4, uint32) = 0x80000000; window_invalidate(w); @@ -1088,6 +1084,12 @@ void window_scenery_scrollpaint() if (sceneryEntry->wall.flags & WALL_SCENERY_HAS_SECONDARY_COLOUR) { imageId |= (window_scenery_secondary_colour << 24) | 0x80000000; } + gfx_draw_sprite(clipdpi, imageId, 0x2F, (sceneryEntry->wall.height * 2) + 0x32, + tertiaryColour); + + imageId = (sceneryEntry->image + 0x40000006) | (window_scenery_primary_colour << 19); + gfx_draw_sprite(clipdpi, imageId, 0x2F, (sceneryEntry->wall.height * 2) + 0x32, + tertiaryColour); } else { imageId |= (window_scenery_primary_colour << 19) | 0x20000000; @@ -1100,11 +1102,17 @@ void window_scenery_scrollpaint() tertiaryColour = window_scenery_tertiary_colour; } + } + gfx_draw_sprite(clipdpi, imageId, 0x2F, (sceneryEntry->wall.height * 2) + 0x32, + tertiaryColour); + + if (sceneryEntry->wall.flags & WALL_SCENERY_FLAG5){ + gfx_draw_sprite(clipdpi, imageId + 1, 0x2F, (sceneryEntry->wall.height * 2) + 0x32, + tertiaryColour); } } - gfx_draw_sprite(clipdpi, imageId, 0x2F, (sceneryEntry->wall.height * 2) + 0x32, - tertiaryColour); + rct2_free(clipdpi); } } diff --git a/src/window_scenery.h b/src/windows/scenery.h similarity index 100% rename from src/window_scenery.h rename to src/windows/scenery.h diff --git a/src/windows/shortcut_key_change.c b/src/windows/shortcut_key_change.c new file mode 100644 index 0000000000..fe735a7a6b --- /dev/null +++ b/src/windows/shortcut_key_change.c @@ -0,0 +1,128 @@ +/***************************************************************************** +* Copyright (c) 2014 Ted John, Duncan Frost +* OpenRCT2, an open source clone of Roller Coaster Tycoon 2. +* +* This file is part of OpenRCT2. +* +* OpenRCT2 is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. + +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. + +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*****************************************************************************/ + +#include "../addresses.h" +#include "../config.h" +#include "../interface/window.h" +#include "../interface/widget.h" +#include "../localisation/localisation.h" + +#define WW 250 +#define WH 60 + +enum WINDOW_SHORTCUT_CHANGE_WIDGET_IDX { + WIDX_BACKGROUND, + WIDX_TITLE, + WIDX_CLOSE, +}; + +// 0x9DE4E0 +static rct_widget window_shortcut_change_widgets[] = { + { WWT_FRAME, 0, 0, WW - 1, 0, WH - 1, STR_NONE, STR_NONE }, + { WWT_CAPTION, 0, 1, WW - 2, 1, 14, STR_OPTIONS, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, WW-13, WW - 3, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WIDGETS_END } +}; + +static void window_shortcut_change_emptysub(){} +static void window_shortcut_change_mouseup(); +static void window_shortcut_change_paint(); + +//0x9A3F7C +static void* window_shortcut_change_events[] = { + window_shortcut_change_emptysub, + window_shortcut_change_mouseup, + window_shortcut_change_emptysub, + window_shortcut_change_emptysub, + window_shortcut_change_emptysub, + window_shortcut_change_emptysub, + window_shortcut_change_emptysub, + window_shortcut_change_emptysub, + window_shortcut_change_emptysub, + window_shortcut_change_emptysub, + window_shortcut_change_emptysub, + window_shortcut_change_emptysub, + window_shortcut_change_emptysub, + window_shortcut_change_emptysub, + window_shortcut_change_emptysub, + window_shortcut_change_emptysub, + window_shortcut_change_emptysub, + window_shortcut_change_emptysub, + window_shortcut_change_emptysub, + window_shortcut_change_emptysub, + window_shortcut_change_emptysub, + window_shortcut_change_emptysub, + window_shortcut_change_emptysub, + window_shortcut_change_emptysub, + window_shortcut_change_emptysub, + window_shortcut_change_emptysub, + window_shortcut_change_paint, + window_shortcut_change_emptysub +}; + +void window_shortcut_change_open(int selected_key){ + // Move this to window_shortcut_change_open + window_close_by_id(WC_CHANGE_KEYBOARD_SHORTCUT, 0); + // Save the item we are selecting for new window + RCT2_GLOBAL(0x9DE511, uint8) = selected_key; + rct_window* w = window_create_auto_pos(WW, WH, (uint32*)window_shortcut_change_events, WC_CHANGE_KEYBOARD_SHORTCUT, 0); + + w->widgets = window_shortcut_change_widgets; + w->enabled_widgets = (1 << 2); + window_init_scroll_widgets(w); + w->colours[0] = 7; + w->colours[1] = 7; + w->colours[2] = 7; +} + +/** +* +* rct2: 0x006E3AE0 +*/ +static void window_shortcut_change_mouseup(){ + short widgetIndex; + rct_window *w; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex){ + case WIDX_CLOSE: + window_close(w); + } +} + +/** +* +* rct2: 0x006E3A9F +*/ +static void window_shortcut_change_paint(){ + rct_window *w; + rct_drawpixelinfo *dpi; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + + int x = w->x + 125; + int y = w->y + 30; + + RCT2_GLOBAL(0x13CE952, uint16) = 2493 + RCT2_GLOBAL(0x9DE511, uint8); + gfx_draw_string_centred_wrapped(dpi, (void*)0x13CE952, x, y, 242, 2785, RCT2_GLOBAL(0x9DEB8D, uint8)); +} \ No newline at end of file diff --git a/src/windows/shortcut_keys.c b/src/windows/shortcut_keys.c new file mode 100644 index 0000000000..29d8be2032 --- /dev/null +++ b/src/windows/shortcut_keys.c @@ -0,0 +1,275 @@ +/***************************************************************************** +* Copyright (c) 2014 Ted John, Duncan Frost +* OpenRCT2, an open source clone of Roller Coaster Tycoon 2. +* +* This file is part of OpenRCT2. +* +* OpenRCT2 is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. + +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. + +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*****************************************************************************/ + +#include "../addresses.h" +#include "../config.h" +#include "../interface/window.h" +#include "../interface/widget.h" +#include "../localisation/localisation.h" +#include "../platform/osinterface.h" + +#define WW 340 +#define WH 240 + +enum WINDOW_SHORTCUT_WIDGET_IDX { + WIDX_BACKGROUND, + WIDX_TITLE, + WIDX_CLOSE, + WIDX_SCROLL, + WIDX_RESET +}; + +// 0x9DE48C +static rct_widget window_shortcut_widgets[] = { + { WWT_FRAME, 0, 0, WW - 1, 0, WH - 1, STR_NONE, STR_NONE }, + { WWT_CAPTION, 0, 1, WW - 2, 1, 14, STR_OPTIONS, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, WW-13, WW - 3, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WWT_SCROLL, 0, 4, WW - 5, 18, WH - 18, 2, 2786 }, + { WWT_DROPDOWN_BUTTON, 0, 4, 153, WH-15, WH - 4, 2491, 2492 }, + { WIDGETS_END } +}; + +void window_shortcut_emptysub() { } +static void window_shortcut_mouseup(); +static void window_shortcut_paint(); +static void window_shortcut_tooltip(); +static void window_shortcut_scrollgetsize(); +static void window_shortcut_scrollmousedown(); +static void window_shortcut_scrollmouseover(); +static void window_shortcut_scrollpaint(); + +static void* window_shortcut_events[] = { + window_shortcut_emptysub, + window_shortcut_mouseup, + window_shortcut_emptysub, + window_shortcut_emptysub, + window_shortcut_emptysub, + window_shortcut_emptysub, + window_shortcut_emptysub, + window_shortcut_emptysub, + window_shortcut_emptysub, + window_shortcut_emptysub, + window_shortcut_emptysub, + window_shortcut_emptysub, + window_shortcut_emptysub, + window_shortcut_emptysub, + window_shortcut_emptysub, + window_shortcut_scrollgetsize, + window_shortcut_scrollmousedown, + window_shortcut_emptysub, + window_shortcut_scrollmouseover, + window_shortcut_emptysub, + window_shortcut_emptysub, + window_shortcut_emptysub, + window_shortcut_tooltip, + window_shortcut_emptysub, + window_shortcut_emptysub, + window_shortcut_emptysub, + window_shortcut_paint, + window_shortcut_scrollpaint +}; + +/** + * + * rct2: 0x006E3884 + */ +void window_shortcut_keys_open() +{ + rct_window* w; + + w = window_bring_to_front_by_id(WC_KEYBOARD_SHORTCUT_LIST, 0); + + if (w) return; + + w = window_create_auto_pos(WW, WH, (uint32*)window_shortcut_events, WC_KEYBOARD_SHORTCUT_LIST, 0); + + w->widgets = window_shortcut_widgets; + w->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_RESET); + window_init_scroll_widgets(w); + + w->colours[0] = 7; + w->colours[1] = 7; + w->colours[2] = 7; + w->no_list_items = 32; + w->selected_list_item = -1; +} + +/** +* +* rct2: 0x006E39E4 +*/ +static void window_shortcut_mouseup() +{ + short widgetIndex; + rct_window *w; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex){ + case WIDX_CLOSE: + window_close(w); + break; + case WIDX_RESET: + config_reset_shortcut_keys(); + config_save(); + window_invalidate(w); + break; + } +} + +/** +* +* rct2: 0x006E38E0 +*/ +static void window_shortcut_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); +} + +/** +* +* rct2: 0x006E3A0C +*/ +static void window_shortcut_tooltip() +{ + RCT2_GLOBAL(0x013CE952, uint16) = STR_LIST; +} + +/** +* +* rct2: 0x006E3A07 +*/ +static void window_shortcut_scrollgetsize() +{ + int y; + rct_window *w; + window_get_register(w); + + y = 32 * 10; + +#ifdef _MSC_VER + __asm mov edx, y +#else + __asm__("mov edx, %[y] " : [y] "+m" (y)); +#endif +} + +/** +* +* rct2: 0x006E3A3E +*/ +static void window_shortcut_scrollmousedown() +{ + short x, y; + rct_window *w; + + window_scrollmouse_get_registers(w, x, y); + + int selected_item = y / 10; + + if (selected_item >= w->no_list_items)return; + + window_shortcut_change_open(selected_item); +} + +/** +* +* rct2: 0x006E3A16 +*/ +static void window_shortcut_scrollmouseover() +{ + short x, y; + rct_window *w; + + window_scrollmouse_get_registers(w, x, y); + + int selected_item = y / 10; + + if (selected_item >= w->no_list_items)return; + + w->selected_list_item = selected_item; + + window_invalidate(w); +} + +/** + * + * rct2: 0x006E38E6 + */ +static void window_shortcut_scrollpaint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + + window_paint_get_registers(w, dpi); + + gfx_fill_rect(dpi, dpi->x, dpi->y, dpi->x + dpi->width - 1, dpi->y + dpi->height - 1, RCT2_ADDRESS(0x0141FC48,uint8)[w->colours[1] * 8]); + + for (int i = 0; i < w->no_list_items; ++i){ + int y = i * 10; + if (y > dpi->y + dpi->height) { + break; + } + if (y + 10 < dpi->y)continue; + int format = STR_BLACK_STRING; + if (i == w->selected_list_item){ + format = STR_WINDOW_COLOUR_2_STRING; + gfx_fill_rect(dpi, 0, y, 800, y + 9, 0x2000031); + } + + RCT2_GLOBAL(0x13CE954, uint16) = i + STR_SHORTCUT_DESCRIPTION_0; + RCT2_GLOBAL(0x13CE956, uint16) = 0; + RCT2_GLOBAL(0x13CE958, uint16) = 0; + + // This is the original version that will not take into account remapped keys. + //shortcut_entry sc_entry = RCT2_ADDRESS(RCT2_ADDRESS_CONFIG_KEYBOARD_SHORTCUTS, shortcut_entry)[i]; + //if (sc_entry.key != 255){ + // RCT2_GLOBAL(0x13CE958, uint16) = sc_entry.key + 2525; + // if (sc_entry.modifier){ + // RCT2_GLOBAL(0x13CE956, uint16) = 2782; + // if (sc_entry.key != 1){ + // RCT2_GLOBAL(0x13CE956, uint16) = 2783; + // } + // } + //} + + uint16 shortcut_entry = gShortcutKeys[i]; + if (shortcut_entry != 0xFFFF){ + RCT2_GLOBAL(0x13CE958, uint16) = STR_INDIVIDUAL_KEYS_BASE + osinterface_scancode_to_rct_keycode(shortcut_entry & 0xFF); + //Display the modifer + if (shortcut_entry & 0x100){ + RCT2_GLOBAL(0x13CE956, uint16) = STR_SHIFT_PLUS; + } + else if (shortcut_entry & 0x200){ + RCT2_GLOBAL(0x13CE956, uint16) = STR_CTRL_PLUS; + } + } + + + RCT2_GLOBAL(0x13CE952, uint16) = STR_SHORTCUT_ENTRY_FORMAT; + + gfx_draw_string_left(dpi, format, (void*)0x13CE952, 0, 0, y - 1); + } +} \ No newline at end of file diff --git a/src/window_staff_peep.c b/src/windows/staff.c similarity index 68% rename from src/window_staff_peep.c rename to src/windows/staff.c index 555818c920..90583588c2 100644 --- a/src/window_staff_peep.c +++ b/src/windows/staff.c @@ -18,24 +18,25 @@ * along with this program. If not, see . *****************************************************************************/ -#include "addresses.h" -#include "game.h" -#include "peep.h" -#include "string_ids.h" -#include "sprite.h" -#include "sprites.h" -#include "viewport.h" -#include "widget.h" -#include "window.h" -#include "window_dropdown.h" +#include "../addresses.h" +#include "../game.h" +#include "../interface/viewport.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../localisation/localisation.h" +#include "../peep/peep.h" +#include "../peep/staff.h" +#include "../sprites.h" +#include "../world/sprite.h" +#include "dropdown.h" -enum WINDOW_STAFF_PEEP_PAGE { - WINDOW_STAFF_PEEP_OVERVIEW, - WINDOW_STAFF_PEEP_OPTIONS, - WINDOW_STAFF_PEEP_STATISTICS, +enum WINDOW_STAFF_PAGE { + WINDOW_STAFF_OVERVIEW, + WINDOW_STAFF_OPTIONS, + WINDOW_STAFF_STATISTICS, }; -enum WINDOW_STAFF_PEEP_WIDGET_IDX { +enum WINDOW_STAFF_WIDGET_IDX { WIDX_BACKGROUND, WIDX_TITLE, WIDX_CLOSE, @@ -60,9 +61,9 @@ enum WINDOW_STAFF_PEEP_WIDGET_IDX { WIDX_COSTUME = 0xD, }; -void window_staff_peep_emptysub(){}; +void window_staff_emptysub(){}; -rct_widget window_staff_peep_overview_widgets[] = { +rct_widget window_staff_overview_widgets[] = { { WWT_FRAME, 0, 0, 189, 0, 179, 0x0FFFFFFFF, STR_NONE }, // Panel / Background { WWT_CAPTION, 0, 1, 188, 1, 14, 0x361, STR_WINDOW_TITLE_TIP }, // Title { WWT_CLOSEBOX, 0, 177, 187, 2, 13, 0x338, STR_CLOSE_WINDOW_TIP }, // Close x button @@ -81,132 +82,132 @@ rct_widget window_staff_peep_overview_widgets[] = { { WIDGETS_END }, }; -rct_widget *window_staff_peep_page_widgets[] = { - window_staff_peep_overview_widgets, +rct_widget *window_staff_page_widgets[] = { + window_staff_overview_widgets, (rct_widget *)0x9AF910, (rct_widget *)0x9AF9F4 }; -void window_staff_peep_set_page(rct_window* w, int page); -void window_staff_peep_disable_widgets(rct_window* w); +void window_staff_set_page(rct_window* w, int page); +void window_staff_disable_widgets(rct_window* w); -void window_staff_peep_overview_close(); -void window_staff_peep_overview_mouseup(); -void window_staff_peep_overview_resize(); -void window_staff_peep_overview_mousedown(int widgetIndex, rct_window* w, rct_widget* widget); -void window_staff_peep_overview_dropdown(); -void window_staff_peep_overview_update(rct_window* w); +void window_staff_overview_close(); +void window_staff_overview_mouseup(); +void window_staff_overview_resize(); +void window_staff_overview_mousedown(int widgetIndex, rct_window* w, rct_widget* widget); +void window_staff_overview_dropdown(); +void window_staff_overview_update(rct_window* w); -void window_staff_peep_orders_mouseup(); -void window_staff_peep_orders_update(rct_window* w); +void window_staff_orders_mouseup(); +void window_staff_orders_update(rct_window* w); -void window_staff_peep_stats_mouseup(); -void window_staff_peep_stats_resize(); -void window_staff_peep_stats_update(rct_window* w); +void window_staff_stats_mouseup(); +void window_staff_stats_resize(); +void window_staff_stats_update(rct_window* w); // 0x992AEC -static void* window_staff_peep_overview_events[] = { - window_staff_peep_overview_close, - window_staff_peep_overview_mouseup, - window_staff_peep_overview_resize, - window_staff_peep_overview_mousedown, - window_staff_peep_overview_dropdown, - window_staff_peep_emptysub, - window_staff_peep_overview_update, - window_staff_peep_emptysub, - window_staff_peep_emptysub, +static void* window_staff_overview_events[] = { + window_staff_overview_close, + window_staff_overview_mouseup, + window_staff_overview_resize, + window_staff_overview_mousedown, + window_staff_overview_dropdown, + window_staff_emptysub, + window_staff_overview_update, + window_staff_emptysub, + window_staff_emptysub, (void*)0x6BDFD8, (void*)0x6BDFC3, - window_staff_peep_emptysub, - window_staff_peep_emptysub, + window_staff_emptysub, + window_staff_emptysub, (void*)0x6BDFAE, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, (void*)0x6BDFED, (void*)0x6BE5FC, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, (void*)0x6BDD91, //Invalidate (void*)0x6BDEAF, //Paint - window_staff_peep_emptysub + window_staff_emptysub }; // 0x992B5C -static void* window_staff_peep_orders_events[] = { - window_staff_peep_emptysub, - window_staff_peep_orders_mouseup, - window_staff_peep_stats_resize, +static void* window_staff_orders_events[] = { + window_staff_emptysub, + window_staff_orders_mouseup, + window_staff_stats_resize, (void*)0x6BE802, (void*)0x6BE809, (void*)0x6BE9DA, - window_staff_peep_orders_update, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, + window_staff_orders_update, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, (void*)0x6BE62B, //Invalidate (void*)0x6BE7C6, //Paint - window_staff_peep_emptysub + window_staff_emptysub }; // 0x992BCC -static void* window_staff_peep_stats_events[] = { - window_staff_peep_emptysub, - window_staff_peep_stats_mouseup, - window_staff_peep_stats_resize, - window_staff_peep_emptysub, - window_staff_peep_emptysub, +static void* window_staff_stats_events[] = { + window_staff_emptysub, + window_staff_stats_mouseup, + window_staff_stats_resize, + window_staff_emptysub, + window_staff_emptysub, (void*)0x6BEC80, - window_staff_peep_stats_update, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, - window_staff_peep_emptysub, + window_staff_stats_update, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, + window_staff_emptysub, (void*)0x6BE9E9, //Invalidate (void*)0x6BEA86, //Paint - window_staff_peep_emptysub + window_staff_emptysub }; -void* window_staff_peep_page_events[] = { - window_staff_peep_overview_events, - window_staff_peep_orders_events, - window_staff_peep_stats_events +void* window_staff_page_events[] = { + window_staff_overview_events, + window_staff_orders_events, + window_staff_stats_events }; -uint32 window_staff_peep_page_enabled_widgets[] = { +uint32 window_staff_page_enabled_widgets[] = { (1 << WIDX_CLOSE) | (1 << WIDX_TAB_1) | (1 << WIDX_TAB_2) | @@ -237,11 +238,11 @@ uint32 window_staff_peep_page_enabled_widgets[] = { * * rct2: 0x006BEE98 */ -void window_staff_peep_open(rct_peep* peep) +void window_staff_open(rct_peep* peep) { rct_window* w = window_bring_to_front_by_id(WC_PEEP, peep->sprite_index); if (w == NULL) { - w = window_create_auto_pos(190, 180, (uint32*)window_staff_peep_overview_events, WC_PEEP, (uint16)0x400); + w = window_create_auto_pos(190, 180, (uint32*)window_staff_overview_events, WC_PEEP, (uint16)0x400); w->widgets = RCT2_GLOBAL(0x9AF81C, rct_widget*); w->enabled_widgets = RCT2_GLOBAL(0x9929B0, uint32); @@ -252,7 +253,7 @@ void window_staff_peep_open(rct_peep* peep) RCT2_GLOBAL((int*)w + 0x496, uint16) = 0; // missing, var_494 should perhaps be uint16? - window_staff_peep_disable_widgets(w); + window_staff_disable_widgets(w); w->min_width = 190; w->min_height = 180; @@ -268,12 +269,12 @@ void window_staff_peep_open(rct_peep* peep) w->page = 0; window_invalidate(w); - w->widgets = window_staff_peep_overview_widgets; - w->enabled_widgets = window_staff_peep_page_enabled_widgets[0]; + w->widgets = window_staff_overview_widgets; + w->enabled_widgets = window_staff_page_enabled_widgets[0]; w->var_020 = RCT2_GLOBAL(0x9929BC, uint32); - w->event_handlers = window_staff_peep_page_events[0]; + w->event_handlers = window_staff_page_events[0]; w->pressed_widgets = 0; - window_staff_peep_disable_widgets(w); + window_staff_disable_widgets(w); window_init_scroll_widgets(w); RCT2_CALLPROC_X(0x006BEDA3, 0, 0, 0, 0, (int)w, 0, 0); if (g_sprite_list[w->number].peep.state == PEEP_STATE_PICKED) { @@ -285,7 +286,7 @@ void window_staff_peep_open(rct_peep* peep) * rct2: 0x006BED21 * Disable the staff pickup if not in pickup state. */ -void window_staff_peep_disable_widgets(rct_window* w) +void window_staff_disable_widgets(rct_window* w) { rct_peep* peep = &g_sprite_list[w->number].peep; @@ -332,10 +333,10 @@ void window_staff_peep_disable_widgets(rct_window* w) } /** - * Same as window_peep_close. + * Same as window_peep_overview_close. * rct2: 0x006BDFF8 */ -void window_staff_peep_overview_close() +void window_staff_overview_close() { rct_window* w; @@ -349,7 +350,7 @@ void window_staff_peep_overview_close() } /** rct2: 0x6C0A77 */ -void window_staff_peep_fire(rct_window* w) +void window_staff_fire(rct_window* w) { // Check if the confirm window already exists. if (window_bring_to_front_by_id(0x1A, w->number)) { @@ -379,7 +380,7 @@ void window_staff_peep_fire(rct_window* w) * Mostly similar to window_peep_set_page. * rct2: 0x006BE023 */ -void window_staff_peep_set_page(rct_window* w, int page) +void window_staff_set_page(rct_window* w, int page) { if (RCT2_GLOBAL(0x9DE518,uint32) & (1 << 3)) { @@ -390,7 +391,7 @@ void window_staff_peep_set_page(rct_window* w, int page) } int listen = 0; - if (page == WINDOW_STAFF_PEEP_OVERVIEW && w->page == WINDOW_STAFF_PEEP_OVERVIEW && w->viewport){ + if (page == WINDOW_STAFF_OVERVIEW && w->page == WINDOW_STAFF_OVERVIEW && w->viewport){ if (!(w->viewport->flags & VIEWPORT_FLAG_SOUND_ON)) listen = 1; } @@ -405,13 +406,13 @@ void window_staff_peep_set_page(rct_window* w, int page) viewport->width = 0; } - w->enabled_widgets = window_staff_peep_page_enabled_widgets[page]; + w->enabled_widgets = window_staff_page_enabled_widgets[page]; w->var_020 = RCT2_ADDRESS(0x9929BC, uint32)[page]; - w->event_handlers = window_staff_peep_page_events[page]; + w->event_handlers = window_staff_page_events[page]; w->pressed_widgets = 0; - w->widgets = window_staff_peep_page_widgets[page]; + w->widgets = window_staff_page_widgets[page]; - window_staff_peep_disable_widgets(w); + window_staff_disable_widgets(w); window_invalidate(w); RCT2_CALLPROC_X(w->event_handlers[WE_RESIZE], 0, 0, 0, 0, (int)w, 0, 0); @@ -424,7 +425,7 @@ void window_staff_peep_set_page(rct_window* w, int page) } /** rct2: 0x006BDF55 */ -void window_staff_peep_overview_mouseup() +void window_staff_overview_mouseup() { short widgetIndex; rct_window* w; @@ -438,7 +439,7 @@ void window_staff_peep_overview_mouseup() case WIDX_TAB_1: case WIDX_TAB_2: case WIDX_TAB_3: - window_staff_peep_set_page(w, widgetIndex - WIDX_TAB_1); + window_staff_set_page(w, widgetIndex - WIDX_TAB_1); break; case WIDX_LOCATE: // 0xD window_scroll_to_viewport(w); @@ -460,7 +461,7 @@ void window_staff_peep_overview_mouseup() RCT2_CALLPROC_X(0x0069A42F, 0, 0, 0, 0, (int)peep, 0, 0); break; case WIDX_FIRE: // 0xE - window_staff_peep_fire(w); + window_staff_fire(w); break; case WIDX_RENAME: // 0xC // 6BE4BC @@ -470,12 +471,12 @@ void window_staff_peep_overview_mouseup() } /** rct2: 0x006BE558 */ -void window_staff_peep_overview_resize() +void window_staff_overview_resize() { rct_window* w; window_get_register(w); - window_staff_peep_disable_widgets(w); + window_staff_disable_widgets(w); w->min_width = 190; w->max_width = 500; @@ -524,7 +525,7 @@ void window_staff_peep_overview_resize() * Handle the dropdown of patrol button. * rct2: 0x006BDF98 */ -void window_staff_peep_overview_mousedown(int widgetIndex, rct_window* w, rct_widget* widget) +void window_staff_overview_mousedown(int widgetIndex, rct_window* w, rct_widget* widget) { if (widgetIndex != WIDX_PATROL) { return; @@ -543,13 +544,13 @@ void window_staff_peep_overview_mousedown(int widgetIndex, rct_window* w, rct_wi rct_peep* peep = GET_PEEP(w->number); // Disable clear patrol area if no area is set. - if (!(RCT2_ADDRESS(0x013CA672, uint8)[peep->var_C5] & 2)) { + if (!(RCT2_ADDRESS(RCT2_ADDRESS_STAFF_MODE_ARRAY, uint8)[peep->staff_id] & 2)) { RCT2_GLOBAL(0x009DED34, sint32) |= 1 << 1; } } /** rct2: 0x006BDFA3 */ -void window_staff_peep_overview_dropdown() +void window_staff_overview_dropdown() { short widgetIndex, dropdownIndex; rct_window* w; @@ -563,17 +564,18 @@ void window_staff_peep_overview_dropdown() // Clear patrol if (dropdownIndex == 1) { rct_peep* peep = GET_PEEP(w->number); - int edi = peep->var_C5; + int edi = peep->staff_id; int ebx = edi << 9; for (int i = 0; i < 128; i++) { RCT2_GLOBAL(0x13B0E72 + ebx + i * 4, uint32) = 0; } - RCT2_GLOBAL(0x13CA672 + edi, uint16) &= 0xFD; // bug?? + RCT2_GLOBAL(RCT2_ADDRESS_STAFF_MODE_ARRAY + edi, uint16) &= 0xFD; // bug?? window_invalidate(w); - RCT2_CALLPROC_EBPSAFE(0x006C0C3F); + //RCT2_CALLPROC_EBPSAFE(0x006C0C3F); + sub_6C0C3F(); } else { if (!tool_set(w, widgetIndex, 22)) { @@ -588,7 +590,7 @@ void window_staff_peep_overview_dropdown() * Update the animation frame of the tab icon. * rct2: 0x6BE602 */ -void window_staff_peep_overview_update(rct_window* w) +void window_staff_overview_update(rct_window* w) { int var_496 = RCT2_GLOBAL((int)w + 0x496, uint16); var_496++; @@ -600,7 +602,7 @@ void window_staff_peep_overview_update(rct_window* w) } /** rct2: 0x006BE814 */ -void window_staff_peep_set_order(rct_window* w, int order_id) +void window_staff_set_order(rct_window* w, int order_id) { int eax = 1 << order_id; @@ -613,7 +615,7 @@ void window_staff_peep_set_order(rct_window* w, int order_id) } /** rct2: 0x006BE7DB */ -void window_staff_peep_orders_mouseup() +void window_staff_orders_mouseup() { short widgetIndex; rct_window* w; @@ -626,26 +628,26 @@ void window_staff_peep_orders_mouseup() case WIDX_TAB_1: case WIDX_TAB_2: case WIDX_TAB_3: - window_staff_peep_set_page(w, widgetIndex - WIDX_TAB_1); + window_staff_set_page(w, widgetIndex - WIDX_TAB_1); break; case WIDX_CHECKBOX_1: case WIDX_CHECKBOX_2: case WIDX_CHECKBOX_3: case WIDX_CHECKBOX_4: - window_staff_peep_set_order(w, widgetIndex - WIDX_CHECKBOX_1); + window_staff_set_order(w, widgetIndex - WIDX_CHECKBOX_1); break; } } /** rct2: 0x006BE960 */ -void window_staff_peep_orders_update(rct_window* w) +void window_staff_orders_update(rct_window* w) { w->frame_no++; window_invalidate_by_id(0x597, w->number); } /** rct2: 0x006BEBCF */ -void window_staff_peep_stats_mouseup() +void window_staff_stats_mouseup() { short widgetIndex; rct_window* w; @@ -658,13 +660,13 @@ void window_staff_peep_stats_mouseup() case WIDX_TAB_1: case WIDX_TAB_2: case WIDX_TAB_3: - window_staff_peep_set_page(w, widgetIndex - WIDX_TAB_1); + window_staff_set_page(w, widgetIndex - WIDX_TAB_1); break; } } /** rct2: 0x006BEC1B and rct2: 0x006BE975 */ -void window_staff_peep_stats_resize() +void window_staff_stats_resize() { rct_window* w; window_get_register(w); @@ -696,7 +698,7 @@ void window_staff_peep_stats_resize() } /** rct2: 0x006BEBEA */ -void window_staff_peep_stats_update(rct_window* w) +void window_staff_stats_update(rct_window* w) { w->frame_no++; window_invalidate_by_id(0x697, w->number); diff --git a/src/window_staff.c b/src/windows/staff_list.c similarity index 54% rename from src/window_staff.c rename to src/windows/staff_list.c index eed1574ee7..5fdc51c99c 100644 --- a/src/window_staff.c +++ b/src/windows/staff_list.c @@ -19,122 +19,123 @@ *****************************************************************************/ #include -#include "addresses.h" -#include "game.h" -#include "gfx.h" -#include "peep.h" -#include "staff.h" -#include "sprite.h" -#include "string_ids.h" -#include "viewport.h" -#include "widget.h" -#include "window.h" +#include "../addresses.h" +#include "../game.h" +#include "../drawing/drawing.h" +#include "../interface/viewport.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../localisation/localisation.h" +#include "../peep/peep.h" +#include "../peep/staff.h" +#include "../world/sprite.h" +#include "dropdown.h" enum { - WINDOW_STAFF_TAB_HANDYMEN, - WINDOW_STAFF_TAB_MECHANICS, - WINDOW_STAFF_TAB_SECURITY, - WINDOW_STAFF_TAB_ENTERTAINERS + WINDOW_STAFF_LIST_TAB_HANDYMEN, + WINDOW_STAFF_LIST_TAB_MECHANICS, + WINDOW_STAFF_LIST_TAB_SECURITY, + WINDOW_STAFF_LIST_TAB_ENTERTAINERS } WINDOW_STAFF_LIST_TAB; -static void window_staff_emptysub() { } -static void window_staff_close(); -static void window_staff_mouseup(); -static void window_staff_resize(); -static void window_staff_mousedown(int widgetIndex, rct_window*w, rct_widget* widget); -static void window_staff_dropdown(); -static void window_staff_update(rct_window *w); -static void window_staff_tooldown(); -static void window_staff_toolabort(); -static void window_staff_scrollgetsize(); -static void window_staff_scrollmousedown(); -static void window_staff_scrollmouseover(); -static void window_staff_tooltip(); -static void window_staff_invalidate(); -static void window_staff_paint(); -static void window_staff_scrollpaint(); +static void window_staff_list_emptysub() { } +static void window_staff_list_close(); +static void window_staff_list_mouseup(); +static void window_staff_list_resize(); +static void window_staff_list_mousedown(int widgetIndex, rct_window*w, rct_widget* widget); +static void window_staff_list_dropdown(); +static void window_staff_list_update(rct_window *w); +static void window_staff_list_tooldown(); +static void window_staff_list_toolabort(); +static void window_staff_list_scrollgetsize(); +static void window_staff_list_scrollmousedown(); +static void window_staff_list_scrollmouseover(); +static void window_staff_list_tooltip(); +static void window_staff_list_invalidate(); +static void window_staff_list_paint(); +static void window_staff_list_scrollpaint(); -static void* window_staff_events[] = { - window_staff_close, - window_staff_mouseup, - window_staff_resize, - window_staff_mousedown, - window_staff_dropdown, - window_staff_emptysub, - window_staff_update, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, - (void*)0x006BD990, // window_staff_tooldown - window_staff_emptysub, - window_staff_emptysub, - window_staff_toolabort, - window_staff_emptysub, - window_staff_scrollgetsize, - window_staff_scrollmousedown, - window_staff_emptysub, - window_staff_scrollmouseover, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, - window_staff_tooltip, - window_staff_emptysub, - window_staff_emptysub, - window_staff_invalidate, - window_staff_paint, - window_staff_scrollpaint, +static void* window_staff_list_events[] = { + window_staff_list_close, + window_staff_list_mouseup, + window_staff_list_resize, + window_staff_list_mousedown, + window_staff_list_dropdown, + window_staff_list_emptysub, + window_staff_list_update, + window_staff_list_emptysub, + window_staff_list_emptysub, + window_staff_list_emptysub, + (void*)0x006BD990, // window_staff_list_tooldown + window_staff_list_emptysub, + window_staff_list_emptysub, + window_staff_list_toolabort, + window_staff_list_emptysub, + window_staff_list_scrollgetsize, + window_staff_list_scrollmousedown, + window_staff_list_emptysub, + window_staff_list_scrollmouseover, + window_staff_list_emptysub, + window_staff_list_emptysub, + window_staff_list_emptysub, + window_staff_list_tooltip, + window_staff_list_emptysub, + window_staff_list_emptysub, + window_staff_list_invalidate, + window_staff_list_paint, + window_staff_list_scrollpaint, }; enum WINDOW_STAFF_LIST_WIDGET_IDX { - WIDX_STAFF_BACKGROUND, - WIDX_STAFF_TITLE, - WIDX_STAFF_CLOSE, - WIDX_STAFF_TAB_CONTENT_PANEL, - WIDX_STAFF_HANDYMEN_TAB, - WIDX_STAFF_MECHANICS_TAB, - WIDX_STAFF_SECURITY_TAB, - WIDX_STAFF_ENTERTAINERS_TAB, - WIDX_STAFF_LIST, - WIDX_STAFF_UNIFORM_COLOR_PICKER, - WIDX_STAFF_HIRE_BUTTON, - WIDX_STAFF_SHOW_PATROL_AREA_BUTTON, - WIDX_STAFF_MAP, + WIDX_STAFF_LIST_BACKGROUND, + WIDX_STAFF_LIST_TITLE, + WIDX_STAFF_LIST_CLOSE, + WIDX_STAFF_LIST_TAB_CONTENT_PANEL, + WIDX_STAFF_LIST_HANDYMEN_TAB, + WIDX_STAFF_LIST_MECHANICS_TAB, + WIDX_STAFF_LIST_SECURITY_TAB, + WIDX_STAFF_LIST_ENTERTAINERS_TAB, + WIDX_STAFF_LIST_LIST, + WIDX_STAFF_LIST_UNIFORM_COLOR_PICKER, + WIDX_STAFF_LIST_HIRE_BUTTON, + WIDX_STAFF_LIST_SHOW_PATROL_AREA_BUTTON, + WIDX_STAFF_LIST_MAP, }; -static rct_widget window_staff_widgets[] = { - { WWT_FRAME, 0, 0, 319, 0, 269, 0x0FFFFFFFF, STR_NONE }, // panel / background - { WWT_CAPTION, 0, 1, 318, 1, 14, STR_STAFF, STR_WINDOW_TITLE_TIP }, // title bar - { WWT_CLOSEBOX, 0, 307, 317, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, // close button - { WWT_RESIZE, 1, 0, 319, 43, 269, 0x0FFFFFFFF, STR_NONE }, // tab content panel - { WWT_TAB, 1, 3, 33, 17, 43, 0x02000144E, STR_STAFF_HANDYMEN_TAB_TIP }, // handymen tab - { WWT_TAB, 1, 34, 64, 17, 43, 0x02000144E, STR_STAFF_MECHANICS_TAB_TIP }, // mechanics tab - { WWT_TAB, 1, 65, 95, 17, 43, 0x02000144E, STR_STAFF_SECURITY_TAB_TIP }, // security guards tab - { WWT_TAB, 1, 96, 126, 17, 43, 0x02000144E, STR_STAFF_ENTERTAINERS_TAB_TIP }, // entertainers tab - { WWT_SCROLL, 1, 3, 316, 72, 266, 3, STR_NONE }, // staff list - { WWT_COLORBTN, 1, 130, 141, 58, 69, STR_NONE, STR_UNIFORM_COLOUR_TIP }, // uniform color picker - { WWT_DROPDOWN_BUTTON, 0, 165, 309, 17, 29, STR_NONE, STR_HIRE_STAFF_TIP }, // hire button - { WWT_FLATBTN, 1, 267, 290, 46, 69, 5175, STR_SHOW_PATROL_AREA_TIP }, // show staff patrol area tool - { WWT_FLATBTN, 1, 291, 314, 46, 69, 5192, STR_SHOW_STAFF_ON_MAP_TIP }, // show staff on map button - { WIDGETS_END }, +static rct_widget window_staff_list_widgets[] = { + { WWT_FRAME, 0, 0, 319, 0, 269, 0x0FFFFFFFF, STR_NONE }, // panel / background + { WWT_CAPTION, 0, 1, 318, 1, 14, STR_STAFF, STR_WINDOW_TITLE_TIP }, // title bar + { WWT_CLOSEBOX, 0, 307, 317, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, // close button + { WWT_RESIZE, 1, 0, 319, 43, 269, 0x0FFFFFFFF, STR_NONE }, // tab content panel + { WWT_TAB, 1, 3, 33, 17, 43, 0x02000144E, STR_STAFF_HANDYMEN_TAB_TIP }, // handymen tab + { WWT_TAB, 1, 34, 64, 17, 43, 0x02000144E, STR_STAFF_MECHANICS_TAB_TIP }, // mechanics tab + { WWT_TAB, 1, 65, 95, 17, 43, 0x02000144E, STR_STAFF_SECURITY_TAB_TIP }, // security guards tab + { WWT_TAB, 1, 96, 126, 17, 43, 0x02000144E, STR_STAFF_ENTERTAINERS_TAB_TIP }, // entertainers tab + { WWT_SCROLL, 1, 3, 316, 72, 266, 3, STR_NONE }, // staff list + { WWT_COLORBTN, 1, 130, 141, 58, 69, STR_NONE, STR_UNIFORM_COLOUR_TIP }, // uniform color picker + { WWT_DROPDOWN_BUTTON, 0, 165, 309, 17, 29, STR_NONE, STR_HIRE_STAFF_TIP }, // hire button + { WWT_FLATBTN, 1, 267, 290, 46, 69, 5175, STR_SHOW_PATROL_AREA_TIP }, // show staff patrol area tool + { WWT_FLATBTN, 1, 291, 314, 46, 69, 5192, STR_SHOW_STAFF_ON_MAP_TIP }, // show staff on map button + { WIDGETS_END }, }; -static uint16 _window_staff_selected_type_count = 0; +static uint16 _window_staff_list_selected_type_count = 0; // TODO: These are still referenced in non-decompiled code -//static int _window_staff_highlighted_index; -//static int _window_staff_selected_tab; +//static int _window_staff_list_highlighted_index; +//static int _window_staff_list_selected_tab; /* * rct2: 0x006BD39C **/ -void window_staff_init_vars() +void window_staff_list_init_vars() { - RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_STAFF_LIST_SELECTED_TAB, uint8) = WINDOW_STAFF_TAB_HANDYMEN; + RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_STAFF_LIST_SELECTED_TAB, uint8) = WINDOW_STAFF_LIST_TAB_HANDYMEN; } /* * rct2: 0x006BD3CC **/ -void window_staff_open() +void window_staff_list_open() { rct_window* window; @@ -143,24 +144,24 @@ void window_staff_open() if (window != NULL) return; - window = window_create_auto_pos(320, 270, (uint32*)window_staff_events, WC_STAFF_LIST, 0x0400); - window->widgets = window_staff_widgets; + window = window_create_auto_pos(320, 270, (uint32*)window_staff_list_events, WC_STAFF_LIST, 0x0400); + window->widgets = window_staff_list_widgets; window->enabled_widgets = - (1 << WIDX_STAFF_CLOSE) | - (1 << WIDX_STAFF_HANDYMEN_TAB) | - (1 << WIDX_STAFF_MECHANICS_TAB) | - (1 << WIDX_STAFF_SECURITY_TAB) | - (1 << WIDX_STAFF_ENTERTAINERS_TAB) | - (1 << WIDX_STAFF_HIRE_BUTTON) | - (1 << WIDX_STAFF_UNIFORM_COLOR_PICKER) | - (1 << WIDX_STAFF_SHOW_PATROL_AREA_BUTTON) | - (1 << WIDX_STAFF_MAP); + (1 << WIDX_STAFF_LIST_CLOSE) | + (1 << WIDX_STAFF_LIST_HANDYMEN_TAB) | + (1 << WIDX_STAFF_LIST_MECHANICS_TAB) | + (1 << WIDX_STAFF_LIST_SECURITY_TAB) | + (1 << WIDX_STAFF_LIST_ENTERTAINERS_TAB) | + (1 << WIDX_STAFF_LIST_HIRE_BUTTON) | + (1 << WIDX_STAFF_LIST_UNIFORM_COLOR_PICKER) | + (1 << WIDX_STAFF_LIST_SHOW_PATROL_AREA_BUTTON) | + (1 << WIDX_STAFF_LIST_MAP); window_init_scroll_widgets(window); RCT2_GLOBAL(RCT2_ADDRESS_STAFF_HIGHLIGHTED_INDEX, short) = -1; window->list_information_type = 0; - window_staff_widgets[WIDX_STAFF_UNIFORM_COLOR_PICKER].type = WWT_EMPTY; + window_staff_list_widgets[WIDX_STAFF_LIST_UNIFORM_COLOR_PICKER].type = WWT_EMPTY; window->min_width = 320; window->min_height = 270; window->max_width = 500; @@ -171,7 +172,7 @@ void window_staff_open() window->colours[2] = 4; } -void window_staff_cancel_tools(rct_window *w) { +void window_staff_list_cancel_tools(rct_window *w) { int toolWindowClassification = RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass); int toolWindowNumber = RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber); if (RCT2_GLOBAL(0x009DE518, uint32) & (1 << 3)) @@ -182,19 +183,19 @@ void window_staff_cancel_tools(rct_window *w) { /* * rct2: 0x006BD9B1 **/ -void window_staff_close() { +void window_staff_list_close() { rct_window *w; window_get_register(w); - window_staff_cancel_tools(w); + window_staff_list_cancel_tools(w); } /** * * rct2: 0x006BD94C */ -static void window_staff_mouseup() +static void window_staff_list_mouseup() { short widgetIndex; rct_window *w; @@ -203,31 +204,31 @@ static void window_staff_mouseup() window_widget_get_registers(w, widgetIndex); switch (widgetIndex) { - case WIDX_STAFF_CLOSE: + case WIDX_STAFF_LIST_CLOSE: window_close(w); break; - case WIDX_STAFF_HIRE_BUTTON: + case WIDX_STAFF_LIST_HIRE_BUTTON: newStaffId = hire_new_staff_member(RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_STAFF_LIST_SELECTED_TAB, uint8)); if (newStaffId == 0xFFFF) { rct_window* window = window_find_by_id(WC_STAFF_LIST, 0); window_invalidate(window); } else { - window_staff_peep_open(&g_sprite_list[newStaffId].peep); + window_staff_open(&g_sprite_list[newStaffId].peep); } break; - case WIDX_STAFF_SHOW_PATROL_AREA_BUTTON: + case WIDX_STAFF_LIST_SHOW_PATROL_AREA_BUTTON: RCT2_CALLPROC_X(0x006BD9FF, 0, 0, 0, widgetIndex, (int)w, 0, 0); // TODO: The code below works, but due to some funny things, when clicking again on the show patrol area button to disable the tool, // the mouseup event is getting called when it should not be - //tool_set(w, WIDX_STAFF_SHOW_PATROL_AREA_BUTTON, 0x0C); + //tool_set(w, WIDX_STAFF_LIST_SHOW_PATROL_AREA_BUTTON, 0x0C); //show_gridlines(); //RCT2_GLOBAL(0x009DEA50, uint16) = RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_STAFF_LIST_SELECTED_TAB, uint8) | 0x8000; //gfx_invalidate_screen(); break; - case WIDX_STAFF_MAP: + case WIDX_STAFF_LIST_MAP: window_map_open(); break; } @@ -237,7 +238,7 @@ static void window_staff_mouseup() * * rct2: 0x006BDD5D */ -static void window_staff_resize() +static void window_staff_list_resize() { rct_window *w; @@ -260,27 +261,25 @@ static void window_staff_resize() * * rct2: 0x006BD971 */ -static void window_staff_mousedown(int widgetIndex, rct_window* w, rct_widget* widget) +static void window_staff_list_mousedown(int widgetIndex, rct_window* w, rct_widget* widget) { short newSelectedTab; - int eax; switch (widgetIndex) { - case WIDX_STAFF_HANDYMEN_TAB: - case WIDX_STAFF_MECHANICS_TAB: - case WIDX_STAFF_SECURITY_TAB: - case WIDX_STAFF_ENTERTAINERS_TAB: - newSelectedTab = widgetIndex - WIDX_STAFF_HANDYMEN_TAB;; + case WIDX_STAFF_LIST_HANDYMEN_TAB: + case WIDX_STAFF_LIST_MECHANICS_TAB: + case WIDX_STAFF_LIST_SECURITY_TAB: + case WIDX_STAFF_LIST_ENTERTAINERS_TAB: + newSelectedTab = widgetIndex - WIDX_STAFF_LIST_HANDYMEN_TAB;; if (RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_STAFF_LIST_SELECTED_TAB, uint8) == newSelectedTab) break; RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_STAFF_LIST_SELECTED_TAB, uint8) = (uint8)newSelectedTab; window_invalidate(w); w->scrolls[0].v_top = 0; - window_staff_cancel_tools(w); + window_staff_list_cancel_tools(w); break; - case WIDX_STAFF_UNIFORM_COLOR_PICKER: - eax = (RCT2_ADDRESS(RCT2_ADDRESS_HANDYMAN_COLOUR, uint8)[RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_STAFF_LIST_SELECTED_TAB, uint8)] << 8) + 0x80 + w->colours[1]; - RCT2_CALLPROC_X(0x006ED43D, eax, 0, 0, widgetIndex, (int)w, (int)widget, 0xFFFFFFFF); + case WIDX_STAFF_LIST_UNIFORM_COLOR_PICKER: + window_dropdown_show_colour(w, widget, w->colours[1], RCT2_ADDRESS(RCT2_ADDRESS_HANDYMAN_COLOUR, uint8)[RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_STAFF_LIST_SELECTED_TAB, uint8)]); break; } @@ -291,13 +290,13 @@ static void window_staff_mousedown(int widgetIndex, rct_window* w, rct_widget* w * * rct2: 0x006BD9A6 */ -static void window_staff_dropdown() +static void window_staff_list_dropdown() { rct_window* w; short widgetIndex, dropdownIndex; window_dropdown_get_registers(w, widgetIndex, dropdownIndex); - if (widgetIndex == WIDX_STAFF_UNIFORM_COLOR_PICKER && dropdownIndex != -1) { + if (widgetIndex == WIDX_STAFF_LIST_UNIFORM_COLOR_PICKER && dropdownIndex != -1) { update_staff_colour(RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_STAFF_LIST_SELECTED_TAB, uint8), dropdownIndex); } } @@ -306,7 +305,7 @@ static void window_staff_dropdown() * * rct2: 0x006BDCEA */ -void window_staff_update(rct_window *w) +void window_staff_list_update(rct_window *w) { int spriteIndex; rct_peep *peep; @@ -315,7 +314,7 @@ void window_staff_update(rct_window *w) if (w->list_information_type >= 24) { w->list_information_type = 0; } else { - widget_invalidate(WC_GUEST_LIST, 0, WIDX_STAFF_HANDYMEN_TAB + RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_STAFF_LIST_SELECTED_TAB, uint8)); + widget_invalidate(WC_GUEST_LIST, 0, WIDX_STAFF_LIST_HANDYMEN_TAB + RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_STAFF_LIST_SELECTED_TAB, uint8)); RCT2_GLOBAL(0x009AC861, uint16) |= 2; FOR_ALL_PEEPS(spriteIndex, peep) { if (peep->type == PEEP_TYPE_STAFF) { @@ -333,13 +332,13 @@ void window_staff_update(rct_window *w) * * rct2: 0x006BD99B */ -void window_staff_toolabort() { +void window_staff_list_toolabort() { short widgetIndex; rct_window *w; window_widget_get_registers(w, widgetIndex); - if (widgetIndex == WIDX_STAFF_SHOW_PATROL_AREA_BUTTON) { + if (widgetIndex == WIDX_STAFF_LIST_SHOW_PATROL_AREA_BUTTON) { hide_gridlines(); tool_cancel(); RCT2_GLOBAL(0x009DEA50, sint16) = 0xFFFF; @@ -351,7 +350,7 @@ void window_staff_toolabort() { * * rct2: 0x006BDBE6 */ -void window_staff_scrollgetsize() { +void window_staff_list_scrollgetsize() { int spriteIndex; rct_peep *peep; rct_window *w; @@ -364,7 +363,7 @@ void window_staff_scrollgetsize() { staffCount++; } - _window_staff_selected_type_count = staffCount; + _window_staff_list_selected_type_count = staffCount; if (RCT2_GLOBAL(RCT2_ADDRESS_STAFF_HIGHLIGHTED_INDEX, short) != -1) { RCT2_GLOBAL(RCT2_ADDRESS_STAFF_HIGHLIGHTED_INDEX, short) = -1; @@ -372,7 +371,7 @@ void window_staff_scrollgetsize() { } int scrollHeight = staffCount * 10; - int i = scrollHeight - window_staff_widgets[WIDX_STAFF_LIST].bottom + window_staff_widgets[WIDX_STAFF_LIST].top + 21; + int i = scrollHeight - window_staff_list_widgets[WIDX_STAFF_LIST_LIST].bottom + window_staff_list_widgets[WIDX_STAFF_LIST_LIST].top + 21; if (i < 0) i = 0; if (i < w->scrolls[0].v_top) { @@ -397,7 +396,7 @@ void window_staff_scrollgetsize() { * * rct2: 0x006BDC9A */ -void window_staff_scrollmousedown() { +void window_staff_list_scrollmousedown() { int i, spriteIndex; short x, y; rct_window *w; @@ -414,7 +413,7 @@ void window_staff_scrollmousedown() { continue; if (i == 0) { - window_staff_peep_open(peep); + window_staff_open(peep); break; } @@ -426,7 +425,7 @@ void window_staff_scrollmousedown() { * * rct2: 0x006BDC6B */ -void window_staff_scrollmouseover() { +void window_staff_list_scrollmouseover() { int i; short x, y; rct_window *w; @@ -444,7 +443,7 @@ void window_staff_scrollmouseover() { * * rct2: 0x006BDC90 */ -void window_staff_tooltip() +void window_staff_list_tooltip() { RCT2_GLOBAL(0x013CE952, uint16) = STR_LIST; } @@ -453,7 +452,7 @@ void window_staff_tooltip() * * rct2: 0x006BD477 */ -void window_staff_invalidate() +void window_staff_list_invalidate() { rct_window *w; @@ -464,32 +463,32 @@ void window_staff_invalidate() uint8 widgetIndex = tabIndex + 4; w->pressed_widgets = pressed_widgets | (1 << widgetIndex); - window_staff_widgets[WIDX_STAFF_HIRE_BUTTON].image = STR_HIRE_HANDYMAN + tabIndex; - window_staff_widgets[WIDX_STAFF_UNIFORM_COLOR_PICKER].type = WWT_EMPTY; + window_staff_list_widgets[WIDX_STAFF_LIST_HIRE_BUTTON].image = STR_HIRE_HANDYMAN + tabIndex; + window_staff_list_widgets[WIDX_STAFF_LIST_UNIFORM_COLOR_PICKER].type = WWT_EMPTY; if (tabIndex < 3) { - window_staff_widgets[WIDX_STAFF_UNIFORM_COLOR_PICKER].type = WWT_COLORBTN; - window_staff_widgets[WIDX_STAFF_UNIFORM_COLOR_PICKER].image = + window_staff_list_widgets[WIDX_STAFF_LIST_UNIFORM_COLOR_PICKER].type = WWT_COLORBTN; + window_staff_list_widgets[WIDX_STAFF_LIST_UNIFORM_COLOR_PICKER].image = ((uint32)RCT2_ADDRESS(RCT2_ADDRESS_HANDYMAN_COLOUR, uint8)[tabIndex] << 19) + 0x600013C3; } - window_staff_widgets[WIDX_STAFF_BACKGROUND].right = w->width - 1; - window_staff_widgets[WIDX_STAFF_BACKGROUND].bottom = w->height - 1; - window_staff_widgets[WIDX_STAFF_TAB_CONTENT_PANEL].right = w->width - 1; - window_staff_widgets[WIDX_STAFF_TAB_CONTENT_PANEL].bottom = w->height - 1; - window_staff_widgets[WIDX_STAFF_TITLE].right = w->width - 2; - window_staff_widgets[WIDX_STAFF_CLOSE].left = w->width - 2 - 0x0B; - window_staff_widgets[WIDX_STAFF_CLOSE].right = w->width - 2 - 0x0B + 0x0A; - window_staff_widgets[WIDX_STAFF_LIST].right = w->width - 4; - window_staff_widgets[WIDX_STAFF_LIST].bottom = w->height - 0x0F; + window_staff_list_widgets[WIDX_STAFF_LIST_BACKGROUND].right = w->width - 1; + window_staff_list_widgets[WIDX_STAFF_LIST_BACKGROUND].bottom = w->height - 1; + window_staff_list_widgets[WIDX_STAFF_LIST_TAB_CONTENT_PANEL].right = w->width - 1; + window_staff_list_widgets[WIDX_STAFF_LIST_TAB_CONTENT_PANEL].bottom = w->height - 1; + window_staff_list_widgets[WIDX_STAFF_LIST_TITLE].right = w->width - 2; + window_staff_list_widgets[WIDX_STAFF_LIST_CLOSE].left = w->width - 2 - 0x0B; + window_staff_list_widgets[WIDX_STAFF_LIST_CLOSE].right = w->width - 2 - 0x0B + 0x0A; + window_staff_list_widgets[WIDX_STAFF_LIST_LIST].right = w->width - 4; + window_staff_list_widgets[WIDX_STAFF_LIST_LIST].bottom = w->height - 0x0F; } /** * * rct2: 0x006BD533 */ -void window_staff_paint() { +void window_staff_list_paint() { int i; uint8 selectedTab; rct_window *w; @@ -510,8 +509,8 @@ void window_staff_paint() { gfx_draw_sprite( dpi, i, - (window_staff_widgets[WIDX_STAFF_HANDYMEN_TAB].left + window_staff_widgets[WIDX_STAFF_HANDYMEN_TAB].right) / 2 + w->x, - window_staff_widgets[WIDX_STAFF_HANDYMEN_TAB].bottom - 6 + w->y, 0 + (window_staff_list_widgets[WIDX_STAFF_LIST_HANDYMEN_TAB].left + window_staff_list_widgets[WIDX_STAFF_LIST_HANDYMEN_TAB].right) / 2 + w->x, + window_staff_list_widgets[WIDX_STAFF_LIST_HANDYMEN_TAB].bottom - 6 + w->y, 0 ); // Handymen tab image @@ -522,8 +521,8 @@ void window_staff_paint() { gfx_draw_sprite( dpi, i, - (window_staff_widgets[WIDX_STAFF_MECHANICS_TAB].left + window_staff_widgets[WIDX_STAFF_MECHANICS_TAB].right) / 2 + w->x, - window_staff_widgets[WIDX_STAFF_MECHANICS_TAB].bottom - 6 + w->y, 0 + (window_staff_list_widgets[WIDX_STAFF_LIST_MECHANICS_TAB].left + window_staff_list_widgets[WIDX_STAFF_LIST_MECHANICS_TAB].right) / 2 + w->x, + window_staff_list_widgets[WIDX_STAFF_LIST_MECHANICS_TAB].bottom - 6 + w->y, 0 ); // Security tab image @@ -534,16 +533,16 @@ void window_staff_paint() { gfx_draw_sprite( dpi, i, - (window_staff_widgets[WIDX_STAFF_SECURITY_TAB].left + window_staff_widgets[WIDX_STAFF_SECURITY_TAB].right) / 2 + w->x, - window_staff_widgets[WIDX_STAFF_SECURITY_TAB].bottom - 6 + w->y, 0 + (window_staff_list_widgets[WIDX_STAFF_LIST_SECURITY_TAB].left + window_staff_list_widgets[WIDX_STAFF_LIST_SECURITY_TAB].right) / 2 + w->x, + window_staff_list_widgets[WIDX_STAFF_LIST_SECURITY_TAB].bottom - 6 + w->y, 0 ); rct_drawpixelinfo* sprite_dpi = clip_drawpixelinfo( dpi, - window_staff_widgets[WIDX_STAFF_ENTERTAINERS_TAB].left + w->x + 1, - window_staff_widgets[WIDX_STAFF_ENTERTAINERS_TAB].right - window_staff_widgets[WIDX_STAFF_ENTERTAINERS_TAB].left - 1, - window_staff_widgets[WIDX_STAFF_ENTERTAINERS_TAB].top + w->y + 1, - window_staff_widgets[WIDX_STAFF_ENTERTAINERS_TAB].bottom - window_staff_widgets[WIDX_STAFF_ENTERTAINERS_TAB].top - 1 + window_staff_list_widgets[WIDX_STAFF_LIST_ENTERTAINERS_TAB].left + w->x + 1, + window_staff_list_widgets[WIDX_STAFF_LIST_ENTERTAINERS_TAB].right - window_staff_list_widgets[WIDX_STAFF_LIST_ENTERTAINERS_TAB].left - 1, + window_staff_list_widgets[WIDX_STAFF_LIST_ENTERTAINERS_TAB].top + w->y + 1, + window_staff_list_widgets[WIDX_STAFF_LIST_ENTERTAINERS_TAB].bottom - window_staff_list_widgets[WIDX_STAFF_LIST_ENTERTAINERS_TAB].top - 1 ); @@ -567,26 +566,26 @@ void window_staff_paint() { } if (selectedTab < 3) { - gfx_draw_string_left(dpi, STR_UNIFORM_COLOUR, w, 0, w->x + 6, window_staff_widgets[WIDX_STAFF_UNIFORM_COLOR_PICKER].top + w->y + 1); + gfx_draw_string_left(dpi, STR_UNIFORM_COLOUR, w, 0, w->x + 6, window_staff_list_widgets[WIDX_STAFF_LIST_UNIFORM_COLOR_PICKER].top + w->y + 1); } int staffTypeStringId = 1859 + selectedTab; // If the number of staff for a given type is 1, we use the singular forms of the names - if (_window_staff_selected_type_count == 1) { + if (_window_staff_list_selected_type_count == 1) { staffTypeStringId += 4; } - RCT2_GLOBAL(0x013CE952, uint16) = _window_staff_selected_type_count; + RCT2_GLOBAL(0x013CE952, uint16) = _window_staff_list_selected_type_count; RCT2_GLOBAL(0x013CE952 + 2, uint16) = staffTypeStringId; - gfx_draw_string_left(dpi, STR_STAFF_LIST_COUNTER, (void*)0x013CE952, 0, w->x + 4, window_staff_widgets[WIDX_STAFF_LIST].bottom + w->y + 2); + gfx_draw_string_left(dpi, STR_STAFF_LIST_COUNTER, (void*)0x013CE952, 0, w->x + 4, window_staff_list_widgets[WIDX_STAFF_LIST_LIST].bottom + w->y + 2); } /** * * rct2: 0x006BD785 */ -void window_staff_scrollpaint() +void window_staff_list_scrollpaint() { int spriteIndex, y, i, staffOrderIcon_x, staffOrders, staffOrderSprite; uint32 argument_1, argument_2; @@ -626,7 +625,7 @@ void window_staff_scrollpaint() gfx_draw_string_left_clipped(dpi, format, (void*)0x013CE952, 0, 175, y - 1, 305); // True if a patrol path is set for the worker - if (RCT2_ADDRESS(0x013CA672, uint8)[peep->var_C5] & 2) { + if (RCT2_ADDRESS(RCT2_ADDRESS_STAFF_MODE_ARRAY, uint8)[peep->staff_id] & 2) { gfx_draw_sprite(dpi, 0x13FD, 110, y - 1, 0); } diff --git a/src/window_title_exit.c b/src/windows/title_exit.c similarity index 94% rename from src/window_title_exit.c rename to src/windows/title_exit.c index ecb6426aed..2e8478f5fb 100644 --- a/src/window_title_exit.c +++ b/src/windows/title_exit.c @@ -18,13 +18,12 @@ * along with this program. If not, see . *****************************************************************************/ -#include "addresses.h" -#include "game.h" -#include "sprites.h" -#include "string_ids.h" -#include "widget.h" -#include "window.h" -#include "rct2.h" +#include "../addresses.h" +#include "../game.h" +#include "../sprites.h" +#include "../localisation/localisation.h" +#include "../interface/widget.h" +#include "../interface/window.h" static rct_widget window_title_exit_widgets[] = { { WWT_IMGBTN, 2, 0, 39, 0, 63, SPR_MENU_EXIT, STR_EXIT }, diff --git a/src/window_title_logo.c b/src/windows/title_logo.c similarity index 95% rename from src/window_title_logo.c rename to src/windows/title_logo.c index 2fd9d7c0f0..835ab23d67 100644 --- a/src/window_title_logo.c +++ b/src/windows/title_logo.c @@ -18,11 +18,11 @@ * along with this program. If not, see . *****************************************************************************/ -#include "addresses.h" -#include "string_ids.h" -#include "sprites.h" -#include "widget.h" -#include "window.h" +#include "../addresses.h" +#include "../localisation/localisation.h" +#include "../sprites.h" +#include "../interface/widget.h" +#include "../interface/window.h" static rct_widget window_title_logo_widgets[] = { { WWT_EMPTY, 0, 0, 0, 0, 0, 0xFFFFFFFF, STR_NONE }, diff --git a/src/window_title_menu.c b/src/windows/title_menu.c similarity index 95% rename from src/window_title_menu.c rename to src/windows/title_menu.c index 54aa0ea04c..88bf10d8f5 100644 --- a/src/window_title_menu.c +++ b/src/windows/title_menu.c @@ -18,15 +18,15 @@ * along with this program. If not, see . *****************************************************************************/ -#include "addresses.h" -#include "editor.h" -#include "game.h" -#include "string_ids.h" -#include "sprites.h" -#include "tutorial.h" -#include "widget.h" -#include "window.h" -#include "window_dropdown.h" +#include "../addresses.h" +#include "../editor.h" +#include "../game.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../localisation/localisation.h" +#include "../sprites.h" +#include "../tutorial.h" +#include "dropdown.h" enum { WIDX_START_NEW_GAME, diff --git a/src/window_title_scenarioselect.c b/src/windows/title_scenarioselect.c similarity index 96% rename from src/window_title_scenarioselect.c rename to src/windows/title_scenarioselect.c index 38246736e7..69efd55a7c 100644 --- a/src/window_title_scenarioselect.c +++ b/src/windows/title_scenarioselect.c @@ -19,14 +19,14 @@ *****************************************************************************/ #include -#include "addresses.h" -#include "audio.h" -#include "date.h" -#include "scenario.h" -#include "string_ids.h" -#include "sprites.h" -#include "widget.h" -#include "window.h" +#include "../addresses.h" +#include "../audio/audio.h" +#include "../localisation/date.h" +#include "../localisation/localisation.h" +#include "../scenario.h" +#include "../sprites.h" +#include "../interface/widget.h" +#include "../interface/window.h" enum { WIDX_BACKGROUND, @@ -223,6 +223,7 @@ static void window_scenarioselect_scrollgetsize() } +/* rct2: 0x6780FE */ static void window_scenarioselect_scrollmousedown() { int i; @@ -243,12 +244,13 @@ static void window_scenarioselect_scrollmousedown() if (y >= 0) continue; - sound_play_panned(SOUND_CLICK_1, w->width / 2 + w->x); + sound_play_panned(SOUND_CLICK_1, w->width / 2 + w->x, 0, 0, 0); scenario_load_and_play(scenario); break; } } +/* rct2: 0x678162 */ static void window_scenarioselect_scrollmouseover() { int i; diff --git a/src/window_tooltip.c b/src/windows/tooltip.c similarity index 95% rename from src/window_tooltip.c rename to src/windows/tooltip.c index 3561e81dd1..85164885cd 100644 --- a/src/window_tooltip.c +++ b/src/windows/tooltip.c @@ -20,11 +20,11 @@ #include #include -#include "addresses.h" -#include "string_ids.h" -#include "widget.h" -#include "window.h" -#include "gfx.h" +#include "../addresses.h" +#include "../drawing/drawing.h" +#include "../localisation/localisation.h" +#include "../interface/widget.h" +#include "../interface/window.h" enum { WIDX_BACKGROUND @@ -213,5 +213,7 @@ static void window_tooltip_paint() gfx_draw_pixel(dpi, right - 1, bottom - 1, 0x0200002F); // Text - RCT2_CALLPROC_X(0x006C1DB7, 0, 0, w->x + ((w->width + 1) / 2) - 1, w->y + 1, 0x0141FE44, (int)dpi, RCT2_GLOBAL(0x01420044, uint16)); + left = w->x + ((w->width + 1) / 2) - 1; + top = w->y + 1; + draw_string_centred_raw(dpi, left, top, RCT2_GLOBAL(0x01420044, uint16), (char*)0x0141FE44); } \ No newline at end of file diff --git a/src/window_tooltip.h b/src/windows/tooltip.h similarity index 96% rename from src/window_tooltip.h rename to src/windows/tooltip.h index cf05351929..adff1c3ed6 100644 --- a/src/window_tooltip.h +++ b/src/windows/tooltip.h @@ -21,8 +21,7 @@ #ifndef _WINDOW_TOOLTIP_H_ #define _WINDOW_TOOLTIP_H_ -#include "rct2.h" -#include "window.h" +#include "../interface/window.h" void window_tooltip_reset(int x, int y); void window_tooltip_open(rct_window *widgetWindow, int widgetIndex, int x, int y); diff --git a/src/windows/track_list.c b/src/windows/track_list.c new file mode 100644 index 0000000000..34e8b72032 --- /dev/null +++ b/src/windows/track_list.c @@ -0,0 +1,649 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of OpenRCT2. + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#include +#include "../addresses.h" +#include "../audio/audio.h" +#include "../editor.h" +#include "../localisation/localisation.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../ride/ride.h" +#include "../ride/track.h" +#include "../sprites.h" +#include "error.h" + +enum { + WIDX_BACKGROUND, + WIDX_TITLE, + WIDX_CLOSE, + WIDX_TRACK_LIST, + WIDX_TRACK_PREVIEW, + WIDX_ROTATE, + WIDX_TOGGLE_SCENERY +}; + +static rct_widget window_track_list_widgets[] = { + { WWT_FRAME, 0, 0, 599, 0, 399, 0xFFFFFFFF, STR_NONE }, + { WWT_CAPTION, 0, 1, 598, 1, 14, STR_SELECT_DESIGN, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, 587, 597, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WWT_SCROLL, 0, 4, 221, 18, 395, 2, STR_CLICK_ON_DESIGN_TO_BUILD_IT_TIP }, + { WWT_FLATBTN, 0, 224, 595, 18, 236, 0xFFFFFFFF, STR_NONE }, + { WWT_FLATBTN, 0, 574, 597, 374, 397, 5169, STR_ROTATE_90_TIP }, + { WWT_FLATBTN, 0, 574, 597, 350, 373, 5171, STR_TOGGLE_SCENERY_TIP }, + { WIDGETS_END }, +}; + +static void window_track_list_emptysub() { } +static void window_track_list_close(); +static void window_track_list_mouseup(); +static void window_track_list_scrollgetsize(); +static void window_track_list_scrollmousedown(); +static void window_track_list_scrollmouseover(); +static void window_track_list_tooltip(); +static void window_track_list_invalidate(); +static void window_track_list_paint(); +static void window_track_list_scrollpaint(); + +static void* window_track_list_events[] = { + (uint32*)window_track_list_close, + (uint32*)window_track_list_mouseup, + (uint32*)window_track_list_emptysub, + (uint32*)window_track_list_emptysub, + (uint32*)window_track_list_emptysub, + (uint32*)window_track_list_emptysub, + (uint32*)window_track_list_emptysub, + (uint32*)window_track_list_emptysub, + (uint32*)window_track_list_emptysub, + (uint32*)window_track_list_emptysub, + (uint32*)window_track_list_emptysub, + (uint32*)window_track_list_emptysub, + (uint32*)window_track_list_emptysub, + (uint32*)window_track_list_emptysub, + (uint32*)window_track_list_emptysub, + (uint32*)window_track_list_scrollgetsize, + (uint32*)window_track_list_scrollmousedown, + (uint32*)window_track_list_emptysub, + (uint32*)window_track_list_scrollmouseover, + (uint32*)window_track_list_emptysub, + (uint32*)window_track_list_emptysub, + (uint32*)window_track_list_emptysub, + (uint32*)window_track_list_tooltip, + (uint32*)window_track_list_emptysub, + (uint32*)window_track_list_emptysub, + (uint32*)window_track_list_invalidate, + (uint32*)window_track_list_paint, + (uint32*)window_track_list_scrollpaint +}; + +ride_list_item _window_track_list_item; + +void window_track_list_format_name(char *dst, const char *src, char colour) +{ + if (colour != 0) + *dst++ = colour; + *dst++ = FORMAT_OPENQUOTES; + while (*src != '.' && *src != 0) { + *dst++ = *src++; + } + *dst++ = FORMAT_ENDQUOTES; + *dst = 0; +} + +/** + * + * rct2: 0x006CF1A2 + */ +void window_track_list_open(ride_list_item item) +{ + rct_window *w; + int x, y; + void *mem; + + window_close_construction_windows(); + _window_track_list_item = item; + + if (RCT2_GLOBAL(0x00F635ED, uint8) & 1) + window_error_open(STR_WARNING, STR_TOO_MANY_TRACK_DESIGNS_OF_THIS_TYPE); + + mem = malloc(1285292); + if (mem == NULL) + return; + + RCT2_GLOBAL(0x00F44105, void*) = mem; + RCT2_CALLPROC_EBPSAFE(0x006D1DCE); + + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER) { + x = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) / 2 - 300; + y = max(28, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) / 2 - 200); + } else { + x = 0; + y = 29; + } + w = window_create(0, 29, 600, 400, (uint32*)window_track_list_events, WC_TRACK_DESIGN_LIST, 0); + w->widgets = window_track_list_widgets; + w->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_ROTATE) | (1 << WIDX_TOGGLE_SCENERY); + window_init_scroll_widgets(w); + w->colours[0] = 26; + w->colours[1] = 26; + w->colours[2] = 26; + w->track_list.var_480 = 0xFFFF; + w->track_list.var_482 = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER ? 1 : 0; + w->track_list.var_484 = 0; + RCT2_GLOBAL(0x00F44152, uint8) = 0; + window_push_others_right(w); + RCT2_GLOBAL(0x00F440AE, uint8) = 2; +} + +/** + * + * rct2: 0x006CFB82 + */ +static void window_track_list_select(rct_window *w, int index) +{ + uint8 *trackDesignItem, *trackDesignList = (uint8*)0x00F441EC; + rct_track_design *trackDesign; + + w->track_list.var_480 = index; + + sound_play_panned(SOUND_CLICK_1, w->x + (w->width / 2), 0, 0, 0); + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER & 8) && index == 0) { + window_close(w); + ride_construct_new(_window_track_list_item); + return; + } + + if (RCT2_GLOBAL(0x00F44153, uint8) != 0) + RCT2_GLOBAL(0x00F44152, uint8) = 1; + + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER & 8)) + index--; + + trackDesignItem = trackDesignList + (index * 128);; + RCT2_GLOBAL(0x00F4403C, uint8*) = trackDesignItem; + + window_track_list_format_name( + (char*)0x009BC313, + trackDesignItem, + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER & 8 ? + 0 : + FORMAT_WHITE + ); + + subsitute_path((char*)0x0141EF68, (char*)RCT2_ADDRESS_TRACKS_PATH, trackDesignItem); + + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER & 8) { + window_track_manage_open(); + return; + } + + if (!RCT2_CALLPROC_X(0x0067726A, 0, 0, 0, 0, 0, 0, 0)) { + w->track_list.var_480 = 0xFFFF; + window_invalidate(w); + return; + } + + trackDesign = track_get_info(index, NULL); + if (trackDesign->var_06 & 4) + window_error_open(STR_THIS_DESIGN_WILL_BE_BUILT_WITH_AN_ALTERNATIVE_VEHICLE_TYPE, -1); + + window_close(w); + window_track_place_open(); +} + +static int window_track_list_get_list_item_index_from_position(int x, int y) +{ + int index; + uint8 *trackDesignItem, *trackDesignList = (uint8*)0x00F441EC; + + index = 0; + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER & 8)) { + y -= 10; + if (y < 0) + return index; + index++; + } + + for (trackDesignItem = trackDesignList; *trackDesignItem != 0; trackDesignItem += 128) { + y -= 10; + if (y < 0) + return index; + index++; + } + + return -1; +} + +/** + * + * rct2: 0x006CFD76 + */ +static void window_track_list_close() +{ + free(RCT2_GLOBAL(0x00F44105, void*)); +} + +/** + * + * rct2: 0x006CFA31 + */ +static void window_track_list_mouseup() +{ + rct_window *w; + short widgetIndex; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER) { + window_close_by_id(WC_47, w->number); + window_close_by_id(WC_48, w->number); + trackmanager_load(); + } + break; + case WIDX_ROTATE: + RCT2_GLOBAL(0x00F440AE, uint8)++; + RCT2_GLOBAL(0x00F440AE, uint8) %= 4; + window_invalidate(w); + break; + case WIDX_TOGGLE_SCENERY: + RCT2_GLOBAL(0x00F44152, uint8) ^= 1; + RCT2_CALLPROC_EBPSAFE(0x006D1DCE); + window_invalidate(w); + break; + } +} + +/** + * + * rct2: 0x006CFAB0 + */ +static void window_track_list_scrollgetsize() +{ + rct_window *w; + int height; + uint8 *trackDesignItem, *trackDesignList = (uint8*)0x00F441EC; + + window_get_register(w); + + height = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER & 8 ? 0 : 10; + for (trackDesignItem = trackDesignList; *trackDesignItem != 0; trackDesignItem += 128) + height += 10; + + #ifdef _MSC_VER + __asm mov ecx, 0 + #else + __asm__ ( "mov ecx, 0 " ); + #endif + + #ifdef _MSC_VER + __asm mov edx, height + #else + __asm__ ( "mov edx, %[height] " : [height] "+m" (height) ); + #endif +} + +/** + * + * rct2: 0x006CFB39 + */ +static void window_track_list_scrollmousedown() +{ + rct_window *w; + short i, x, y; + + window_scrollmouse_get_registers(w, x, y); + + if (w->track_list.var_484 & 1) + return; + if (RCT2_GLOBAL(0x009DEA6E, uint8) != 0) + return; + + i = window_track_list_get_list_item_index_from_position(x, y); + if (i != -1) + window_track_list_select(w, i); +} + +/** + * + * rct2: 0x006CFAD7 + */ +static void window_track_list_scrollmouseover() +{ + rct_window *w; + short i, x, y; + + window_scrollmouse_get_registers(w, x, y); + + if (w->track_list.var_484 & 1) + return; + if (RCT2_GLOBAL(0x009DEA6E, uint8) != 0) + return; + + i = window_track_list_get_list_item_index_from_position(x, y); + if (i != -1 && w->track_list.var_482 != i) { + w->track_list.var_482 = i; + window_invalidate(w); + } +} + +/** + * + * rct2: 0x006CFD6C + */ +static void window_track_list_tooltip() +{ + RCT2_GLOBAL(0x013CE952, uint16) = STR_LIST; +} + +/** + * + * rct2: 0x006CF2D6 + */ +static void window_track_list_invalidate() +{ + rct_window *w; + rct_ride_type *entry; + rct_string_id stringId; + + window_get_register(w); + + entry = GET_RIDE_ENTRY(_window_track_list_item.entry_index); + + stringId = entry->name; + if (!(entry->var_008 & 0x1000)) + stringId = _window_track_list_item.type + 2; + + RCT2_GLOBAL(0x013CE952, uint16) = stringId; + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER) { + window_track_list_widgets[WIDX_TITLE].image = STR_TRACK_DESIGNS; + window_track_list_widgets[WIDX_TRACK_LIST].tooltip = STR_CLICK_ON_DESIGN_TO_RENAME_OR_DELETE_IT; + } else { + window_track_list_widgets[WIDX_TITLE].image = STR_SELECT_DESIGN; + window_track_list_widgets[WIDX_TRACK_LIST].tooltip = STR_CLICK_ON_DESIGN_TO_BUILD_IT_TIP; + } + + if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER) || w->track_list.var_482 != 0) { + w->pressed_widgets |= 1 << WIDX_TRACK_PREVIEW; + w->disabled_widgets &= ~(1 << WIDX_TRACK_PREVIEW); + window_track_list_widgets[WIDX_ROTATE].type = WWT_FLATBTN; + window_track_list_widgets[WIDX_TOGGLE_SCENERY].type = WWT_FLATBTN; + if (RCT2_GLOBAL(0x00F44152, uint8) == 0) + w->pressed_widgets |= (1 << WIDX_TOGGLE_SCENERY); + else + w->pressed_widgets &= ~(1 << WIDX_TOGGLE_SCENERY); + } else { + w->pressed_widgets &= ~(1 << WIDX_TRACK_PREVIEW); + w->disabled_widgets |= (1 << WIDX_TRACK_PREVIEW); + window_track_list_widgets[WIDX_ROTATE].type = WWT_EMPTY; + window_track_list_widgets[WIDX_TOGGLE_SCENERY].type = WWT_EMPTY; + } +} + +/** + * + * rct2: 0x006CF387 + */ +static void window_track_list_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + rct_widget *widget; + rct_track_design *trackDesign; + uint8 *image, *trackDesignList = (uint8*)0x00F441EC; + uint16 holes, speed, drops, dropHeight, inversions; + fixed32_2dp rating; + int trackIndex, x, y, colour, gForces, airTime; + rct_g1_element tmpElement, *subsituteElement, *g1Elements = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element); + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + + trackIndex = w->track_list.var_482; + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER) { + if (*trackDesignList == 0 || trackIndex == -1) + return; + } else if (trackIndex-- == 0) { + return; + } + + // Track preview + widget = &window_track_list_widgets[WIDX_TRACK_PREVIEW]; + x = w->x + widget->left + 1; + y = w->y + widget->top + 1; + colour = RCT2_GLOBAL(0x0141FC44 + (w->colours[0] * 8), uint8); + gfx_fill_rect(dpi, x, y, x + 369, y + 216, colour); + + trackDesign = track_get_info(trackIndex, &image); + if (trackDesign == NULL) + return; + + subsituteElement = &g1Elements[0]; + tmpElement = *subsituteElement; + subsituteElement->offset = image; + subsituteElement->width = 370; + subsituteElement->height = 217; + subsituteElement->x_offset = 0; + subsituteElement->y_offset = 0; + subsituteElement->flags = G1_FLAG_BMP; + gfx_draw_sprite(dpi, 0, x, y, 0); + *subsituteElement = tmpElement; + + x = w->x + (widget->left + widget->right) / 2; + y = w->y + widget->bottom - 12; + + // Warnings + if ((trackDesign->var_06 & 4) && !(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER)) { + // Vehicle design not available + RCT2_GLOBAL(0x00F44153, uint8) = 0; + gfx_draw_string_centred_clipped(dpi, STR_VEHICLE_DESIGN_UNAVAILABLE, NULL, 0, x, y, 368); + y -= 10; + } + + if (trackDesign->var_06 & 1) { + RCT2_GLOBAL(0x00F44153, uint8) = 1; + if (RCT2_GLOBAL(0x00F44152, uint8) == 0) { + // Scenery not available + gfx_draw_string_centred_clipped(dpi, STR_DESIGN_INCLUDES_SCENERY_WHICH_IS_UNAVAILABLE, NULL, 0, x, y, 368); + y -= 10; + } + } + + // Track design name + window_track_list_format_name((char*)0x009BC677, trackDesignList + (trackIndex * 128), FORMAT_WINDOW_COLOUR_1); + gfx_draw_string_centred_clipped(dpi, 3165, NULL, 0, x, y, 368); + + // Information + x = w->x + widget->left + 1; + y = w->y + widget->bottom + 2; + + if (trackDesign->var_6C & 0x80000000) { + // Six flags logo + gfx_draw_sprite(dpi, SPR_SIX_FLAGS, w->x + widget->right - 50, y + 4, 0); + } + + // Stats + rating = trackDesign->excitement * 10; + gfx_draw_string_left(dpi, STR_TRACK_LIST_EXCITEMENT_RATING, &rating, 0, x, y); + y += 10; + + rating = trackDesign->intensity * 10; + gfx_draw_string_left(dpi, STR_TRACK_LIST_INTENSITY_RATING, &rating, 0, x, y); + y += 10; + + rating = trackDesign->nausea * 10; + gfx_draw_string_left(dpi, STR_TRACK_LIST_NAUSEA_RATING, &rating, 0, x, y); + y += 14; + + if (trackDesign->type != RIDE_TYPE_MAZE) { + if (trackDesign->type == RIDE_TYPE_MINI_GOLF) { + // Holes + holes = trackDesign->holes & 0x1F; + gfx_draw_string_left(dpi, STR_HOLES, &holes, 0, x, y); + y += 10; + } else { + // Maximum speed + speed = ((trackDesign->max_speed << 16) * 9) >> 18; + gfx_draw_string_left(dpi, STR_MAX_SPEED, &speed, 0, x, y); + y += 10; + + // Average speed + speed = ((trackDesign->average_speed << 16) * 9) >> 18; + gfx_draw_string_left(dpi, STR_AVERAGE_SPEED, &speed, 0, x, y); + y += 10; + } + + // Ride length + RCT2_GLOBAL(0x013CE952 + 0, uint16) = 1345; + RCT2_GLOBAL(0x013CE952 + 2, uint16) = trackDesign->ride_length; + gfx_draw_string_left_clipped(dpi, STR_TRACK_LIST_RIDE_LENGTH, (void*)0x013CE952, 0, x, y, 214); + y += 10; + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (trackDesign->type * 8), uint32) & 0x80) { + // Maximum positive vertical Gs + gForces = trackDesign->max_positive_vertical_g * 32; + gfx_draw_string_left(dpi, STR_MAX_POSITIVE_VERTICAL_G, &gForces, 0, x, y); + y += 10; + + // Maximum negative verical Gs + gForces = trackDesign->max_negitive_vertical_g * 32; + gfx_draw_string_left(dpi, STR_MAX_NEGATIVE_VERTICAL_G, &gForces, 0, x, y); + y += 10; + + // Maximum lateral Gs + gForces = trackDesign->max_lateral_g * 32; + gfx_draw_string_left(dpi, STR_MAX_LATERAL_G, &gForces, 0, x, y); + y += 10; + + if (trackDesign->var_07 / 4 >= 2) { + if (trackDesign->total_air_time != 0) { + // Total air time + airTime = trackDesign->total_air_time * 25; + gfx_draw_string_left(dpi, STR_TOTAL_AIR_TIME, &airTime, 0, x, y); + y += 10; + } + } + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (trackDesign->type * 8), uint32) & 0x400) { + // Drops + drops = trackDesign->drops & 0x3F; + gfx_draw_string_left(dpi, STR_DROPS, &drops, 0, x, y); + y += 10; + + // Drop height is multiplied by 0.75 + dropHeight = (trackDesign->highest_drop_height + (trackDesign->highest_drop_height / 2)) / 2; + gfx_draw_string_left(dpi, STR_HIGHEST_DROP_HEIGHT, &drops, 0, x, y); + y += 10; + } + + if (trackDesign->type != RIDE_TYPE_MINI_GOLF) { + inversions = trackDesign->inversions & 0x1F; + if (inversions != 0) { + // Inversions + gfx_draw_string_left(dpi, STR_INVERSIONS, &inversions, 0, x, y); + y += 10; + } + } + y += 4; + + if (trackDesign->space_required_x != 0xFF) { + // Space required + RCT2_GLOBAL(0x013CE952 + 0, uint16) = trackDesign->space_required_x; + RCT2_GLOBAL(0x013CE952 + 2, uint16) = trackDesign->space_required_y; + gfx_draw_string_left(dpi, STR_TRACK_LIST_SPACE_REQUIRED, (void*)0x013CE952, 0, x, y); + y += 10; + } + + if (trackDesign->cost != 0) { + gfx_draw_string_left(dpi, STR_TRACK_LIST_COST_AROUND, &trackDesign->cost, 0, x, y); + y += 14; + } +} + +/** + * + * rct2: 0x006CF8CD + */ +static void window_track_list_scrollpaint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + rct_string_id stringId, stringId2; + int i, x, y, colour; + uint8 *trackDesignItem, *trackDesignList = (uint8*)0x00F441EC; + + window_paint_get_registers(w, dpi); + + colour = RCT2_GLOBAL(0x00141FC48 + (w->colours[0] * 8), uint8); + colour = (colour << 24) | (colour << 16) | (colour << 8) | colour; + gfx_clear(dpi, colour); + + i = 0; + x = 0; + y = 0; + + trackDesignItem = trackDesignList; + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER) { + if (*trackDesignItem == 0) { + // No track designs + gfx_draw_string_left(dpi, STR_NO_TRACK_DESIGNS_OF_THIS_TYPE, NULL, 0, x, y - 1); + return; + } + } else { + // Build custom track item + if (i == w->track_list.var_482) { + // Highlight + gfx_fill_rect(dpi, x, y, w->width, y + 9, 0x2000000 | 49); + stringId = 1193; + } else { + stringId = 1191; + } + + stringId2 = STR_BUILD_CUSTOM_DESIGN; + gfx_draw_string_left(dpi, stringId, &stringId2, 0, x, y - 1); + y += 10; + } + + i++; + while (*trackDesignItem != 0) { + if (y + 10 >= dpi->y && y < dpi->y + dpi->height) { + if (i == w->track_list.var_482) { + // Highlight + gfx_fill_rect(dpi, x, y, w->width, y + 9, 0x2000000 | 49); + stringId = 1193; + } else { + stringId = 1191; + } + + // Draw track name + window_track_list_format_name((char*)0x009BC678, trackDesignItem, 0); + stringId2 = 3165; + gfx_draw_string_left(dpi, stringId, &stringId2, 0, x, y - 1); + } + y += 10; + i++; + trackDesignItem += 128; + } +} \ No newline at end of file diff --git a/src/window_error.c b/src/windows/track_manage.c similarity index 84% rename from src/window_error.c rename to src/windows/track_manage.c index 3a31436928..ebfe54d6c6 100644 --- a/src/window_error.c +++ b/src/windows/track_manage.c @@ -18,14 +18,14 @@ * along with this program. If not, see . *****************************************************************************/ -#include "addresses.h" -#include "window_error.h" +#include "../addresses.h" +#include "../interface/window.h" /** - * - * rct2: 0x0066792F + * + * rct2: 0x006D348F */ -void window_error_open(int stringId, int edx) +void window_track_manage_open() { - RCT2_CALLPROC_X(0x0066792F, 0, stringId, 0, edx, 0, 0, 0); + RCT2_CALLPROC_EBPSAFE(0x006D348F); } \ No newline at end of file diff --git a/src/windows/track_place.c b/src/windows/track_place.c new file mode 100644 index 0000000000..1042f6d0dd --- /dev/null +++ b/src/windows/track_place.c @@ -0,0 +1,678 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of OpenRCT2. + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#include +#include "../addresses.h" +#include "../audio/audio.h" +#include "../game.h" +#include "../sprites.h" +#include "../localisation/localisation.h" +#include "../ride/track.h" +#include "../interface/viewport.h" +#include "../interface/widget.h" +#include "../interface/window.h" + +#define TRACK_MINI_PREVIEW_WIDTH 168 +#define TRACK_MINI_PREVIEW_HEIGHT 78 +#define TRACK_MINI_PREVIEW_SIZE (TRACK_MINI_PREVIEW_WIDTH * TRACK_MINI_PREVIEW_HEIGHT) + +enum { + WIDX_BACKGROUND, + WIDX_TITLE, + WIDX_CLOSE, + WIDX_ROTATE, + WIDX_MIRROR, + WIDX_SELECT_DIFFERENT_DESIGN, + WIDX_PRICE +}; + +static rct_widget window_track_place_widgets[] = { + { WWT_FRAME, 0, 0, 199, 0, 123, 0xFFFFFFFF, STR_NONE }, + { WWT_CAPTION, 0, 1, 198, 1, 14, 3155, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, 187, 197, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WWT_FLATBTN, 0, 173, 196, 83, 106, SPR_ROTATE_ARROW, STR_ROTATE_90_TIP }, + { WWT_FLATBTN, 0, 173, 196, 59, 82, 5170, STR_MIRROR_IMAGE_TIP }, + { WWT_DROPDOWN_BUTTON, 0, 4, 195, 109, 120, STR_SELECT_A_DIFFERENT_DESIGN, STR_GO_BACK_TO_DESIGN_SELECTION_WINDOW_TIP }, + { WWT_EMPTY, 0, 0, 0, 0, 0, 0xFFFFFFFF, STR_NONE }, + { WIDGETS_END }, +}; + +static void window_track_place_emptysub() { } +static void window_track_place_close(); +static void window_track_place_mouseup(); +static void window_track_place_update(rct_window *w); +static void window_track_place_toolupdate(); +static void window_track_place_tooldown(); +static void window_track_place_toolabort(); +static void window_track_place_unknown14(); +static void window_track_place_paint(); + +static void* window_track_place_events[] = { + window_track_place_close, + window_track_place_mouseup, + window_track_place_emptysub, + window_track_place_emptysub, + window_track_place_emptysub, + window_track_place_emptysub, + window_track_place_update, + window_track_place_emptysub, + window_track_place_emptysub, + window_track_place_toolupdate, + window_track_place_tooldown, + window_track_place_emptysub, + window_track_place_emptysub, + window_track_place_toolabort, + window_track_place_emptysub, + window_track_place_emptysub, + window_track_place_emptysub, + window_track_place_emptysub, + window_track_place_emptysub, + window_track_place_unknown14, + window_track_place_emptysub, + window_track_place_emptysub, + window_track_place_emptysub, + window_track_place_emptysub, + window_track_place_emptysub, + window_track_place_emptysub, + window_track_place_paint, + window_track_place_emptysub +}; + +static uint8 *_window_track_place_mini_preview; +static sint16 _window_track_place_last_x; +static sint16 _window_track_place_last_y; + +static uint8 _window_track_place_last_was_valid; +static sint16 _window_track_place_last_valid_x; +static sint16 _window_track_place_last_valid_y; +static sint16 _window_track_place_last_valid_z; +static money32 _window_track_place_last_cost; + +/** + * + * rct2: 0x006D182E + */ +static void window_track_place_clear_mini_preview() +{ + memset(_window_track_place_mini_preview, 220, TRACK_MINI_PREVIEW_SIZE); +} + +/** + * Size: 0x0A + */ +typedef struct { + uint8 var_00; + sint16 x; + sint16 y; + uint8 pad_05[3]; + uint8 var_08; + uint8 unk_09; +} rct_preview_track; + +/** + * Size: 0x04 + */ +typedef struct { + union { + uint32 all; + struct { + sint8 x; + sint8 y; + uint8 unk_2; + uint8 type; + }; + }; +} rct_preview_maze; + +#define swap(x, y) x = x ^ y; y = x ^ y; x = x ^ y; + +/** + * + * rct2: 0x006D1845 + */ +static void window_track_place_draw_mini_preview() +{ + rct_track_design *design = (rct_track_design*)0x009D8178; + uint8 *pixel, colour, *trackPtr, bits; + int i, rotation, pass, x, y, pixelX, pixelY, originX, originY, minX, minY, maxX, maxY; + rct_preview_maze *mazeBlock; + rct_preview_track *trackBlock; + + window_track_place_clear_mini_preview(); + + minX = 0; + minY = 0; + maxX = 0; + maxY = 0; + + // First pass is used to determine the width and height of the image so it can centre it + for (pass = 0; pass < 2; pass++) { + originX = 0; + originY = 0; + if (pass == 1) { + originX -= ((maxX + minX) >> 6) << 5; + originY -= ((maxY + minY) >> 6) << 5; + } + + if (design->type != RIDE_TYPE_MAZE) { + #pragma region Track + + rotation = RCT2_GLOBAL(0x00F440AE, uint8) + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32); + trackPtr = design->preview[0]; + + while (*trackPtr != 255) { + int trackType = *trackPtr; + if (trackType == 101) + trackType = 255; + + // Station track is a lighter colour + colour = RCT2_ADDRESS(0x0099BA64, uint8)[trackType * 16] & 0x10 ? 222 : 218; + + // Follow a single track piece shape + trackBlock = RCT2_ADDRESS(0x00994638, rct_preview_track*)[trackType]; + while (trackBlock->var_00 != 255) { + x = originX; + y = originY; + + switch (rotation & 3) { + case 0: + x += trackBlock->x; + y += trackBlock->y; + break; + case 1: + x += trackBlock->y; + y -= trackBlock->x; + break; + case 2: + x -= trackBlock->x; + y -= trackBlock->y; + break; + case 3: + x -= trackBlock->y; + y += trackBlock->x; + break; + } + + if (pass == 0) { + minX = min(minX, x); + maxX = max(maxX, x); + minY = min(minY, y); + maxY = max(maxY, y); + } else { + pixelX = 80 + ((y / 32) - (x / 32)) * 4; + pixelY = 38 + ((y / 32) + (x / 32)) * 2; + if (pixelX <= 160 && pixelY <= 75) { + pixel = &_window_track_place_mini_preview[pixelY * TRACK_MINI_PREVIEW_WIDTH + pixelX]; + + bits = trackBlock->var_08 << (rotation & 3); + bits = (bits & 0x0F) | ((bits & 0xF0) >> 4); + + for (i = 0; i < 4; i++) { + if (bits & 1) pixel[338 + i] = colour; + if (bits & 2) pixel[168 + i] = colour; + if (bits & 4) pixel[ 2 + i] = colour; + if (bits & 8) pixel[172 + i] = colour; + } + } + } + trackBlock++; + } + + // Change rotation and next position based on track curvature + rotation &= 3; + trackType *= 10; + switch (rotation) { + case 0: + originX += RCT2_GLOBAL(0x009968C1 + trackType, sint16); + originY += RCT2_GLOBAL(0x009968C3 + trackType, sint16); + break; + case 1: + originX += RCT2_GLOBAL(0x009968C3 + trackType, sint16); + originY -= RCT2_GLOBAL(0x009968C1 + trackType, sint16); + break; + case 2: + originX -= RCT2_GLOBAL(0x009968C1 + trackType, sint16); + originY -= RCT2_GLOBAL(0x009968C3 + trackType, sint16); + break; + case 3: + originX -= RCT2_GLOBAL(0x009968C3 + trackType, sint16); + originY += RCT2_GLOBAL(0x009968C1 + trackType, sint16); + break; + } + rotation += RCT2_ADDRESS(0x009968BC, uint8)[trackType] - RCT2_ADDRESS(0x009968BB, uint8)[trackType]; + rotation &= 3; + if (RCT2_ADDRESS(0x009968BC, uint8)[trackType] & 4) + rotation |= 4; + if (!(rotation & 4)) { + originX += RCT2_GLOBAL(0x00993CCC + (rotation * 4), sint16); + originY += RCT2_GLOBAL(0x00993CCE + (rotation * 4), sint16); + } + trackPtr += 2; + } + + #pragma endregion + } else { + #pragma region Maze + + rotation = (RCT2_GLOBAL(0x00F440AE, uint8) + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32)) & 3; + mazeBlock = (rct_preview_maze*)design->preview[0]; + while (mazeBlock->all != 0) { + x = mazeBlock->x * 32; + y = mazeBlock->y * 32; + switch (rotation) { + case 1: + x = -x; + swap(x, y); + break; + case 2: + x = -x; + y = -y; + break; + case 3: + x = -x; + swap(x, y); + break; + } + x += originX; + y += originY; + + // Entrance or exit is a lighter colour + colour = mazeBlock->type == 8 || mazeBlock->type == 128 ? 222 : 218; + + if (pass == 0) { + minX = min(minX, x); + maxX = max(maxX, x); + minY = min(minY, y); + maxY = max(maxY, y); + } else { + pixelX = 80 + ((y / 32) - (x / 32)) * 4; + pixelY = 38 + ((y / 32) + (x / 32)) * 2; + if (pixelX <= 160 && pixelY <= 75) { + pixel = &_window_track_place_mini_preview[pixelY * TRACK_MINI_PREVIEW_WIDTH + pixelX]; + + for (i = 0; i < 4; i++) { + pixel[338 + i] = colour; + pixel[168 + i] = colour; + pixel[ 2 + i] = colour; + pixel[172 + i] = colour; + } + } + } + mazeBlock++; + } + + #pragma endregion + } + } +} + +/** + * + * rct2: 0x0068A15E + */ +static void sub_68A15E(int x, int y, short *ax, short *bx) +{ + int eax, ebx, ecx, edx, esi, edi, ebp; + eax = x; + ebx = y; + RCT2_CALLFUNC_X(0x0068A15E, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + *ax = *((short*)&eax); + *bx = *((short*)&ebx); +} + +/** + * Seems to highlight the surface tiles to match the track layout at the given position but also returns some Z value. + * rct2: 0x006D01B3 + */ +static int sub_6D01B3(int bl, int x, int y, int z) +{ + int eax, ebx, ecx, edx, esi, edi, ebp; + eax = x; + ebx = bl; + ecx = y; + edx = z; + esi = 0; + edi = 0; + ebp = 0; + RCT2_CALLFUNC_X(0x006D01B3, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + return *((short*)&ebx); +} + +/** + * + * rct2: 0x006D017F + */ +static void window_track_place_clear_provisional() +{ + if (_window_track_place_last_was_valid) { + sub_6D01B3( + (RCT2_GLOBAL(0x00F440EB, uint8) << 8) | 6, + _window_track_place_last_valid_x, + _window_track_place_last_valid_y, + _window_track_place_last_valid_z + ); + _window_track_place_last_was_valid = 0; + } +} + +/** + * + * rct2: 0x006D17C6 + */ +static int window_track_place_get_base_z(int x, int y) +{ + rct_map_element *mapElement; + int z; + + mapElement = map_get_surface_element_at(x >> 5, y >> 5); + z = mapElement->base_height * 8; + + // Increase Z above slope + if (mapElement->properties.surface.slope & 0x0F) { + z += 16; + + // Increase Z above double slope + if (mapElement->properties.surface.slope & 0x10) + z += 16; + } + + // Increase Z above water + if (mapElement->properties.surface.terrain & 0x1F) + z = max(z, (mapElement->properties.surface.terrain & 0x1F) << 4); + + return z + sub_6D01B3(3, x, y, z); +} + +static void window_track_place_attempt_placement(int x, int y, int z, int bl, money32 *cost, uint8 *rideIndex) +{ + int eax, ebx, ecx, edx, esi, edi, ebp; + money32 result; + + eax = x; + ebx = bl; + ecx = y; + edi = z; + result = game_do_command_p(GAME_COMMAND_47, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + + if (cost != NULL) *cost = result; + if (rideIndex != NULL) *rideIndex = edi & 0xFF; +} + +/** + * + * rct2: 0x006CFCA0 + */ +void window_track_place_open() +{ + rct_window *w; + + window_close_construction_windows(); + + _window_track_place_mini_preview = malloc(TRACK_MINI_PREVIEW_SIZE); + window_track_place_clear_mini_preview(); + + w = window_create(0, 29, 200, 124, (uint32*)window_track_place_events, WC_TRACK_DESIGN_PLACE, 0); + w->widgets = window_track_place_widgets; + w->enabled_widgets = 4 | 8 | 0x10 | 0x20; + window_init_scroll_widgets(w); + w->colours[0] = 24; + w->colours[1] = 24; + w->colours[2] = 24; + tool_set(w, 6, 12); + RCT2_GLOBAL(0x009DE518, uint32) |= 6; + window_push_others_right(w); + show_gridlines(); + _window_track_place_last_cost = MONEY32_UNDEFINED; + _window_track_place_last_x = 0xFFFF; + RCT2_GLOBAL(0x00F440AE, uint8) = (-RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8)) & 3; + window_track_place_draw_mini_preview(); +} + +/** + * + * rct2: 0x006D0119 + */ +static void window_track_place_close() +{ + window_track_place_clear_provisional(); + viewport_set_visibility(0); + RCT2_CALLPROC_EBPSAFE(0x0068AB1B); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~6; + hide_gridlines(); + free(_window_track_place_mini_preview); +} + +/** + * + * rct2: 0x006CFEAC + */ +static void window_track_place_mouseup() +{ + rct_window *w; + short widgetIndex; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + case WIDX_ROTATE: + window_track_place_clear_provisional(); + RCT2_GLOBAL(0x00F440AE, uint16) = (RCT2_GLOBAL(0x00F440AE, uint16) + 1) & 3; + window_invalidate(w); + _window_track_place_last_x = 0xFFFF; + window_track_place_draw_mini_preview(); + break; + case WIDX_MIRROR: + RCT2_CALLPROC_EBPSAFE(0x006D2436); + RCT2_GLOBAL(0x00F440AE, uint16) = (-RCT2_GLOBAL(0x00F440AE, uint16)) & 3; + window_invalidate(w); + _window_track_place_last_x = 0xFFFF; + window_track_place_draw_mini_preview(); + break; + case WIDX_SELECT_DIFFERENT_DESIGN: + window_close(w); + window_track_list_open(_window_track_list_item); + break; + } +} + +/** + * + * rct2: 0x006CFCA0 + */ +static void window_track_place_update(rct_window *w) +{ + if (!(RCT2_GLOBAL(0x009DE518, uint32) & (1 << 3))) + if (RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) != WC_TRACK_DESIGN_PLACE) + window_close(w); +} + +/** + * + * rct2: 0x006CFF2D + */ +static void window_track_place_toolupdate() +{ + rct_window *w; + short widgetIndex, x, y; + int i, z; + money32 cost; + uint8 rideIndex; + + window_tool_get_registers(w, widgetIndex, x, y); + + RCT2_CALLPROC_EBPSAFE(0x0068AB1B); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~7; + + // Get the tool map position + sub_68A15E(x, y, &x, &y); + if (x == (short)0x8000) { + window_track_place_clear_provisional(); + return; + } + + // Check if tool map position has changed since last update + if (x == _window_track_place_last_x && y == _window_track_place_last_y) { + sub_6D01B3(0, x, y, 0); + return; + } + + cost = MONEY32_UNDEFINED; + + // Get base Z position + z = window_track_place_get_base_z(x, y); + if (RCT2_GLOBAL(0x009DEA6E, uint8) == 0) { + window_track_place_clear_provisional(); + + // Try increasing Z until a feasible placement is found + for (i = 0; i < 7; i++) { + window_track_place_attempt_placement(x, y, z, 105, &cost, &rideIndex); + if (cost != MONEY32_UNDEFINED) { + RCT2_GLOBAL(0x00F440EB, uint16) = rideIndex; + _window_track_place_last_valid_x = x; + _window_track_place_last_valid_y = y; + _window_track_place_last_valid_z = z; + _window_track_place_last_was_valid = 1; + break; + } + z += 8; + } + } + + _window_track_place_last_x = x; + _window_track_place_last_y = y; + if (cost != _window_track_place_last_cost) { + _window_track_place_last_cost = cost; + widget_invalidate(WC_TRACK_DESIGN_PLACE, 0, WIDX_PRICE); + } + + sub_6D01B3(0, x, y, z); +} + +/** + * + * rct2: 0x006CFF34 + */ +static void window_track_place_tooldown() +{ + rct_window *w; + short widgetIndex, x, y, z; + int i; + money32 cost; + uint8 rideIndex; + + window_tool_get_registers(w, widgetIndex, x, y); + + window_track_place_clear_provisional(); + RCT2_CALLPROC_EBPSAFE(0x0068AB1B); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~7; + + sub_68A15E(x, y, &x, &y); + if (x == (short)0x8000) + return; + + // Try increasing Z until a feasible placement is found + z = window_track_place_get_base_z(x, y); + for (i = 0; i < 7; i++) { + RCT2_GLOBAL(0x009A8C29, uint8) |= 1; + window_track_place_attempt_placement(x, y, z, 1, &cost, &rideIndex); + RCT2_GLOBAL(0x009A8C29, uint8) &= ~1; + + if (cost != MONEY32_UNDEFINED) { + window_close_by_id(WC_ERROR, 0); + sound_play_panned(SOUND_PLACE_ITEM, 0x8001, x, y, z); + + RCT2_GLOBAL(0x00F440A7, uint8) = rideIndex; + if (RCT2_GLOBAL(0x00F4414E, uint8) & 1) { + window_ride_main_open(rideIndex); + window_close(w); + } else { + RCT2_CALLPROC_X(0x006CC3FB, 0, 0, 0, rideIndex, 0, 0, 0); + w = window_find_by_id(0x80 | WC_RIDE_CONSTRUCTION, 0); + RCT2_CALLPROC_X(w->event_handlers[WE_MOUSE_UP], 0, 0, 0, 29, (int)w, 0, 0); + } + return; + } + + // Check if player did not have enough funds + if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) == 827) + break; + + z += 8; + } + + // Unable to build track + sound_play_panned(SOUND_ERROR, 0x8001, x, y, z); +} + +/** + * + * rct2: 0x006D015C + */ +static void window_track_place_toolabort() +{ + window_track_place_clear_provisional(); +} + +/** + * + * rct2: 0x006CFF01 + */ +static void window_track_place_unknown14() +{ + window_track_place_draw_mini_preview(); +} + +/** + * + * rct2: 0x006CFD9D + */ +static void window_track_place_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi, *clippedDpi; + rct_g1_element tmpElement, *subsituteElement, *g1Elements = RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element); + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + + // Draw mini tile preview + clippedDpi = clip_drawpixelinfo(dpi, w->x + 4, 168, w->y + 18, 78); + if (clippedDpi != NULL) { + subsituteElement = &g1Elements[0]; + tmpElement = *subsituteElement; + subsituteElement->offset = _window_track_place_mini_preview; + subsituteElement->width = TRACK_MINI_PREVIEW_WIDTH; + subsituteElement->height = TRACK_MINI_PREVIEW_HEIGHT; + subsituteElement->x_offset = 0; + subsituteElement->y_offset = 0; + subsituteElement->flags = 0; + gfx_draw_sprite(clippedDpi, 0, 0, 0, 0); + *subsituteElement = tmpElement; + } + + // Price + if (_window_track_place_last_cost != MONEY32_UNDEFINED) + if (!(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY)) + gfx_draw_string_centred(dpi, STR_COST_LABEL, w->x + 88, w->y + 94, 0, &_window_track_place_last_cost); +} \ No newline at end of file diff --git a/src/window_water.c b/src/windows/water.c similarity index 97% rename from src/window_water.c rename to src/windows/water.c index 0147842f5e..c844df0672 100644 --- a/src/window_water.c +++ b/src/windows/water.c @@ -18,12 +18,12 @@ * along with this program. If not, see . *****************************************************************************/ -#include "addresses.h" -#include "map.h" -#include "string_ids.h" -#include "sprites.h" -#include "widget.h" -#include "window.h" +#include "../addresses.h" +#include "../world/map.h" +#include "../localisation/localisation.h" +#include "../sprites.h" +#include "../interface/widget.h" +#include "../interface/window.h" enum WINDOW_WATER_WIDGET_IDX { WIDX_BACKGROUND, diff --git a/src/climate.c b/src/world/climate.c similarity index 92% rename from src/climate.c rename to src/world/climate.c index af633917fa..2d8d849ce2 100644 --- a/src/climate.c +++ b/src/world/climate.c @@ -18,13 +18,13 @@ * along with this program. If not, see . *****************************************************************************/ -#include "addresses.h" -#include "audio.h" +#include "../addresses.h" +#include "../audio/audio.h" +#include "../audio/mixer.h" +#include "../drawing/drawing.h" +#include "../localisation/date.h" +#include "../scenario.h" #include "climate.h" -#include "date.h" -#include "gfx.h" -#include "rct2.h" -#include "scenario.h" enum { THUNDER_STATUS_NULL = 0, @@ -53,8 +53,10 @@ static const rct_weather_transition* climate_transitions[4]; // Sound data static int _rainVolume = 1; static rct_sound _rainSoundInstance; +static void* _rainSoundChannel; static unsigned int _lightningTimer, _thunderTimer; static rct_sound _thunderSoundInstance[MAX_THUNDER_INSTANCES]; +static void* _thunderSoundChannels[MAX_THUNDER_INSTANCES]; static int _thunderStatus[MAX_THUNDER_INSTANCES] = { THUNDER_STATUS_NULL, THUNDER_STATUS_NULL }; static unsigned int _thunderSoundId; static int _thunderVolume; @@ -204,21 +206,43 @@ static void climate_update_rain_sound() if (_climateCurrentWeatherEffect == 1 || _climateCurrentWeatherEffect == 2) { if (_rainVolume == 1) { // Start playing the rain sound +#ifdef USE_MIXER + _rainSoundChannel = Mixer_Play_Effect(SOUND_RAIN_1, MIXER_LOOP_INFINITE, DStoMixerVolume(-4000), 0.5f, 1, 0); +#else if (sound_prepare(SOUND_RAIN_1, &_rainSoundInstance, 1, RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_SOUND_SW_BUFFER, uint32))) sound_play(&_rainSoundInstance, 1, -4000, 0, 0); +#endif _rainVolume = -4000; } else { // Increase rain sound _rainVolume = min(-1400, _rainVolume + 80); +#ifdef USE_MIXER + if (_rainSoundChannel) { + Mixer_Channel_Volume(_rainSoundChannel, DStoMixerVolume(_rainVolume)); + } +#else sound_set_volume(&_rainSoundInstance, _rainVolume); +#endif } } else if (_rainVolume != 1) { // Decrease rain sound _rainVolume -= 80; if (_rainVolume > -4000) { +#ifdef USE_MIXER + if (_rainSoundChannel) { + Mixer_Channel_Volume(_rainSoundChannel, DStoMixerVolume(_rainVolume)); + } +#else sound_set_volume(&_rainSoundInstance, _rainVolume); +#endif } else { +#ifdef USE_MIXER + if (_rainSoundChannel) { + Mixer_Stop_Channel(_rainSoundChannel); + } +#else sound_stop(&_rainSoundInstance); +#endif _rainVolume = 1; } } @@ -248,10 +272,17 @@ static void climate_update_thunder_sound() if (_thunderStatus[i] == THUNDER_STATUS_NULL) continue; +#ifdef USE_MIXER + if (!Mixer_Channel_IsPlaying(_thunderSoundChannels[i])) { + Mixer_Stop_Channel(_thunderSoundChannels[i]); + _thunderStatus[i] = THUNDER_STATUS_NULL; + } +#else if (!sound_is_playing(&_thunderSoundInstance[i])) { sound_stop(&_thunderSoundInstance[i]); _thunderStatus[i] = THUNDER_STATUS_NULL; } +#endif } } @@ -294,12 +325,20 @@ static void climate_update_thunder() static int climate_play_thunder(int instanceIndex, int soundId, int volume, int pan) { +#ifdef USE_MIXER + _thunderSoundChannels[instanceIndex] = Mixer_Play_Effect(soundId, MIXER_LOOP_NONE, DStoMixerVolume(volume), DStoMixerPan(pan), 1, 0); + if (_thunderSoundChannels[instanceIndex]) { + _thunderStatus[instanceIndex] = THUNDER_STATUS_PLAYING; + return 1; + } +#else if (sound_prepare(soundId, &_thunderSoundInstance[instanceIndex], 1, RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_SOUND_SW_BUFFER, uint32))) { sound_play(&_thunderSoundInstance[instanceIndex], 0, volume, pan, 0); _thunderStatus[instanceIndex] = THUNDER_STATUS_PLAYING; return 1; } +#endif return 0; } diff --git a/src/climate.h b/src/world/climate.h similarity index 98% rename from src/climate.h rename to src/world/climate.h index 9aba03f523..fb52082cf6 100644 --- a/src/climate.h +++ b/src/world/climate.h @@ -21,7 +21,7 @@ #ifndef _CLIMATE_H_ #define _CLIMATE_H_ -#include "rct2.h" +#include "../common.h" enum { CLIMATE_COOL_AND_WET, diff --git a/src/map.c b/src/world/map.c similarity index 93% rename from src/map.c rename to src/world/map.c index f654935c4a..01eb46806b 100644 --- a/src/map.c +++ b/src/world/map.c @@ -18,13 +18,29 @@ * along with this program. If not, see . *****************************************************************************/ -#include "addresses.h" +#include "../addresses.h" +#include "../localisation/date.h" #include "climate.h" -#include "date.h" #include "map.h" static void tiles_init(); +int map_element_get_terrain(rct_map_element *element) +{ + int terrain = (element->properties.surface.terrain >> 5) & 7; + if (element->type & 1) + terrain |= (1 << 3); + return terrain; +} + +int map_element_get_terrain_edge(rct_map_element *element) +{ + int terrain_edge = (element->properties.surface.slope >> 5) & 7; + if (element->type & 128) + terrain_edge |= (1 << 3); + return terrain_edge; +} + void map_element_set_terrain(rct_map_element *element, int terrain) { // Bit 3 for terrain is stored in element.type bit 0 @@ -40,7 +56,7 @@ void map_element_set_terrain(rct_map_element *element, int terrain) void map_element_set_terrain_edge(rct_map_element *element, int terrain) { - // Bit 3 for terrain is stored in element.type bit 0 + // Bit 3 for terrain is stored in element.type bit 7 if (terrain & 8) element->type |= 128; else @@ -48,7 +64,7 @@ void map_element_set_terrain_edge(rct_map_element *element, int terrain) // Bits 0, 1, 2 for terrain are stored in element.slope bit 5, 6, 7 element->properties.surface.slope &= ~0xE0; - element->properties.surface.slope = (terrain & 7) << 5; + element->properties.surface.slope |= (terrain & 7) << 5; } rct_map_element *map_get_surface_element_at(int x, int y) @@ -138,9 +154,10 @@ void map_update_tile_pointers() /** * Return the absolute height of an element, given its (x,y) coordinates + * * ax: x * cx: y - * dx: return + * dx: return remember to & with 0xFFFF if you don't want water affecting results * rct2: 0x00662783 */ int map_element_height(int x, int y) diff --git a/src/map.h b/src/world/map.h similarity index 93% rename from src/map.h rename to src/world/map.h index 6c2cbf8b32..5ce24b4d84 100644 --- a/src/map.h +++ b/src/world/map.h @@ -21,7 +21,7 @@ #ifndef _MAP_H_ #define _MAP_H_ -#include "rct2.h" +#include "../common.h" typedef struct { uint8 slope; //4 @@ -195,6 +195,11 @@ typedef struct { void map_init(); void map_update_tile_pointers(); +int map_element_get_terrain(rct_map_element *element); +int map_element_get_terrain_edge(rct_map_element *element); +void map_element_set_terrain(rct_map_element *element, int terrain); +void map_element_set_terrain_edge(rct_map_element *element, int terrain); +rct_map_element *map_get_surface_element_at(int x, int y); int map_element_height(int x, int y); void sub_68B089(); int map_coord_is_connected(uint16 coordinate, uint8 height, uint8 face_direction); diff --git a/src/park.c b/src/world/park.c similarity index 97% rename from src/park.c rename to src/world/park.c index 3621c3db7f..bca9737ab1 100644 --- a/src/park.c +++ b/src/world/park.c @@ -19,19 +19,20 @@ *****************************************************************************/ #include -#include "addresses.h" -#include "award.h" -#include "finance.h" -#include "map.h" -#include "marketing.h" -#include "news_item.h" +#include "../addresses.h" +#include "../interface/window.h" +#include "../localisation/localisation.h" +#include "../management/award.h" +#include "../management/finance.h" +#include "../management/marketing.h" +#include "../management/news_item.h" +#include "../management/research.h" +#include "../peep/peep.h" +#include "../ride/ride.h" +#include "../scenario.h" +#include "../world/map.h" #include "park.h" -#include "peep.h" -#include "ride.h" -#include "scenario.h" #include "sprite.h" -#include "string_ids.h" -#include "window.h" /** * In a difficult guest generation scenario, no guests will be generated if over this value. @@ -76,9 +77,7 @@ void park_init() for (i = 0; i < 20; i++) RCT2_ADDRESS(0x01358102, uint8)[i] = 0; - RCT2_GLOBAL(0x01358844, uint32) = 0xFFFFFFFF; - RCT2_GLOBAL(0x01358849, uint32) = 0xFFFFFFFE; - RCT2_GLOBAL(0x0135884E, uint32) = 0xFFFFFFFD; + research_reset_items(); finance_init(); for (i = 0; i < 2; i++) @@ -395,7 +394,7 @@ static int park_calculate_guest_generation_probability() continue; if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) continue; - if (ride->var_0E4 < 0x2580000) + if (ride->length[0] < (600 << 16)) continue; if (ride->excitement < RIDE_RATING(6,00)) continue; @@ -467,7 +466,7 @@ static void get_random_peep_spawn(rct2_peep_spawn *spawn) static rct_peep *park_generate_new_guest() { - rct_peep *peep; + rct_peep *peep = NULL; rct2_peep_spawn spawn; get_random_peep_spawn(&spawn); diff --git a/src/park.h b/src/world/park.h similarity index 98% rename from src/park.h rename to src/world/park.h index 8a27dfdc8d..9bd41691a1 100644 --- a/src/park.h +++ b/src/world/park.h @@ -21,7 +21,7 @@ #ifndef _PARK_H_ #define _PARK_H_ -#include "rct2.h" +#include "../common.h" #define DECRYPT_MONEY(money) rol32((money) ^ 0xF4EC9621, 13) #define ENCRYPT_MONEY(money) (ror32((money), 13) ^ 0xF4EC9621) diff --git a/src/scenery.h b/src/world/scenery.h similarity index 98% rename from src/scenery.h rename to src/world/scenery.h index 59704d94c0..c4294038aa 100644 --- a/src/scenery.h +++ b/src/world/scenery.h @@ -21,8 +21,7 @@ #ifndef _SCENERY_H_ #define _SCENERY_H_ -#include "rct2.h" -#include "string_ids.h" +#include "../common.h" typedef struct { uint32 flags; // 0x06 @@ -127,4 +126,6 @@ typedef struct { #define g_pathBitSceneryEntries RCT2_ADDRESS(RCT2_ADDRESS_PATH_BIT_SCENERY_ENTRIES, rct_scenery_entry*) #define g_scenerySetEntries RCT2_ADDRESS(RCT2_ADDRESS_SCENERY_SET_ENTRIES, rct_scenery_set_entry*) +void init_scenery(); + #endif \ No newline at end of file diff --git a/src/sprite.c b/src/world/sprite.c similarity index 99% rename from src/sprite.c rename to src/world/sprite.c index e6d589f5b1..6c6bf44b2d 100644 --- a/src/sprite.c +++ b/src/world/sprite.c @@ -18,8 +18,8 @@ * along with this program. If not, see . *****************************************************************************/ -#include "addresses.h" #include +#include "../addresses.h" #include "sprite.h" rct_sprite* g_sprite_list = RCT2_ADDRESS(RCT2_ADDRESS_SPRITE_LIST, rct_sprite); diff --git a/src/sprite.h b/src/world/sprite.h similarity index 97% rename from src/sprite.h rename to src/world/sprite.h index 567c64af44..28d658371a 100644 --- a/src/sprite.h +++ b/src/world/sprite.h @@ -21,13 +21,13 @@ #ifndef _SPRITE_H_ #define _SPRITE_H_ -#include "rct2.h" +#include "../common.h" +#include "../peep/peep.h" +#include "../ride/vehicle.h" #define SPRITE_INDEX_NULL 0xFFFF #define SPRITE_LOCATION_NULL 0x8000 -#include "peep.h" -#include "vehicle.h" enum SPRITE_IDENTIFIER{ SPRITE_IDENTIFIER_VEHICLE = 0,